1use scirs2_core::ndarray::Array1;
9use scirs2_core::parallel_ops::*;
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 /= num_batches as f64;
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(&self, 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(&self, 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 &self,
1617 prediction: &Array1<f64>,
1618 target: &Array1<f64>,
1619 ) -> Result<Array1<f64>> {
1620 let diff = prediction - target;
1622 let grad = 2.0 * &diff / diff.len() as f64;
1623 Ok(grad)
1624 }
1625
1626 fn compute_gradients(&mut self, loss_gradient: &Array1<f64>) -> Result<Vec<Array1<f64>>> {
1628 let mut gradients = Vec::new();
1629
1630 for layer_idx in 0..self.layers.len() {
1631 let layer_gradient = match self.config.training_config.gradient_method {
1632 GradientMethod::ParameterShift => {
1633 self.compute_parameter_shift_gradient(layer_idx, loss_gradient)?
1634 }
1635 GradientMethod::FiniteDifference => {
1636 self.compute_finite_difference_gradient(layer_idx, loss_gradient)?
1637 }
1638 _ => {
1639 return Err(SimulatorError::InvalidConfiguration(
1640 "Gradient method not implemented".to_string(),
1641 ))
1642 }
1643 };
1644 gradients.push(layer_gradient);
1645 }
1646
1647 Ok(gradients)
1648 }
1649
1650 fn compute_parameter_shift_gradient(
1652 &mut self,
1653 layer_idx: usize,
1654 loss_gradient: &Array1<f64>,
1655 ) -> Result<Array1<f64>> {
1656 let layer = &self.layers[layer_idx];
1657 let parameters = layer.get_parameters();
1658 let mut gradient = Array1::zeros(parameters.len());
1659
1660 let shift = PI / 2.0; for (param_idx, ¶m_val) in parameters.iter().enumerate() {
1663 let mut params_plus = parameters.clone();
1665 params_plus[param_idx] = param_val + shift;
1666 self.layers[layer_idx].set_parameters(¶ms_plus);
1667 let output_plus = self.forward_layer(layer_idx, loss_gradient)?;
1668
1669 let mut params_minus = parameters.clone();
1671 params_minus[param_idx] = param_val - shift;
1672 self.layers[layer_idx].set_parameters(¶ms_minus);
1673 let output_minus = self.forward_layer(layer_idx, loss_gradient)?;
1674
1675 gradient[param_idx] = (output_plus.sum() - output_minus.sum()) / 2.0;
1677
1678 self.layers[layer_idx].set_parameters(¶meters);
1680 }
1681
1682 Ok(gradient)
1683 }
1684
1685 fn compute_finite_difference_gradient(
1687 &mut self,
1688 layer_idx: usize,
1689 loss_gradient: &Array1<f64>,
1690 ) -> Result<Array1<f64>> {
1691 let layer = &self.layers[layer_idx];
1692 let parameters = layer.get_parameters();
1693 let mut gradient = Array1::zeros(parameters.len());
1694
1695 let eps = 1e-6; for (param_idx, ¶m_val) in parameters.iter().enumerate() {
1698 let mut params_plus = parameters.clone();
1700 params_plus[param_idx] = param_val + eps;
1701 self.layers[layer_idx].set_parameters(¶ms_plus);
1702 let output_plus = self.forward_layer(layer_idx, loss_gradient)?;
1703
1704 let mut params_minus = parameters.clone();
1706 params_minus[param_idx] = param_val - eps;
1707 self.layers[layer_idx].set_parameters(¶ms_minus);
1708 let output_minus = self.forward_layer(layer_idx, loss_gradient)?;
1709
1710 gradient[param_idx] = (output_plus.sum() - output_minus.sum()) / (2.0 * eps);
1712
1713 self.layers[layer_idx].set_parameters(¶meters);
1715 }
1716
1717 Ok(gradient)
1718 }
1719
1720 fn forward_layer(&mut self, layer_idx: usize, input: &Array1<f64>) -> Result<Array1<f64>> {
1722 self.forward(input)
1724 }
1725
1726 fn apply_gradients(&mut self, gradients: &[Array1<f64>]) -> Result<()> {
1728 for (layer_idx, gradient) in gradients.iter().enumerate() {
1729 let layer = &mut self.layers[layer_idx];
1730 let mut parameters = layer.get_parameters();
1731
1732 match self.config.training_config.optimizer {
1734 OptimizerType::SGD => {
1735 for (param, grad) in parameters.iter_mut().zip(gradient.iter()) {
1736 *param -= self.config.training_config.learning_rate * grad;
1737 }
1738 }
1739 OptimizerType::Adam => {
1740 for (param, grad) in parameters.iter_mut().zip(gradient.iter()) {
1742 *param -= self.config.training_config.learning_rate * grad;
1743 }
1744 }
1745 _ => {
1746 for (param, grad) in parameters.iter_mut().zip(gradient.iter()) {
1748 *param -= self.config.training_config.learning_rate * grad;
1749 }
1750 }
1751 }
1752
1753 if let Some((min_val, max_val)) =
1755 self.config.training_config.regularization.parameter_bounds
1756 {
1757 for param in &mut parameters {
1758 *param = param.clamp(min_val, max_val);
1759 }
1760 }
1761
1762 layer.set_parameters(¶meters);
1763 }
1764
1765 Ok(())
1766 }
1767
1768 fn get_current_learning_rate(&self, epoch: usize) -> f64 {
1770 let base_lr = self.config.training_config.learning_rate;
1771
1772 match self.config.training_config.lr_schedule {
1773 LearningRateSchedule::Constant => base_lr,
1774 LearningRateSchedule::ExponentialDecay => base_lr * 0.95_f64.powi(epoch as i32),
1775 LearningRateSchedule::StepDecay => {
1776 if epoch % 50 == 0 && epoch > 0 {
1777 base_lr * 0.5_f64.powi((epoch / 50) as i32)
1778 } else {
1779 base_lr
1780 }
1781 }
1782 LearningRateSchedule::CosineAnnealing => {
1783 let progress = epoch as f64 / self.config.training_config.epochs as f64;
1784 base_lr * 0.5 * (1.0 + (PI * progress).cos())
1785 }
1786 _ => base_lr,
1787 }
1788 }
1789
1790 fn update_learning_rate(&mut self, epoch: usize, validation_loss: f64) {
1792 let current_lr = self.get_current_learning_rate(epoch);
1795 self.training_state.current_learning_rate = current_lr;
1796 }
1797
1798 fn compute_quantum_advantage_metrics(&self) -> Result<QuantumAdvantageMetrics> {
1800 Ok(QuantumAdvantageMetrics {
1802 quantum_volume: 0.0,
1803 classical_simulation_cost: 0.0,
1804 quantum_speedup_factor: 1.0,
1805 circuit_depth: self.layers.iter().map(|l| l.get_depth()).sum(),
1806 gate_count: self.layers.iter().map(|l| l.get_gate_count()).sum(),
1807 entanglement_measure: 0.0,
1808 })
1809 }
1810
1811 pub const fn get_stats(&self) -> &QMLStats {
1813 &self.stats
1814 }
1815
1816 pub fn get_training_history(&self) -> &[QMLTrainingResult] {
1818 &self.training_history
1819 }
1820
1821 pub fn get_layers(&self) -> &[Box<dyn QMLLayer>] {
1823 &self.layers
1824 }
1825
1826 pub const fn get_config(&self) -> &QMLConfig {
1828 &self.config
1829 }
1830
1831 pub fn encode_amplitude_public(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1833 self.encode_amplitude(input)
1834 }
1835
1836 pub fn encode_angle_public(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1838 self.encode_angle(input)
1839 }
1840
1841 pub fn encode_basis_public(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1843 self.encode_basis(input)
1844 }
1845
1846 pub fn encode_quantum_feature_map_public(
1848 &self,
1849 input: &Array1<f64>,
1850 ) -> Result<Array1<Complex64>> {
1851 self.encode_quantum_feature_map(input)
1852 }
1853
1854 pub fn measure_pauli_z_expectation_public(
1856 &self,
1857 state: &Array1<Complex64>,
1858 qubit: usize,
1859 ) -> Result<f64> {
1860 self.measure_pauli_z_expectation(state, qubit)
1861 }
1862
1863 pub fn get_current_learning_rate_public(&self, epoch: usize) -> f64 {
1865 self.get_current_learning_rate(epoch)
1866 }
1867
1868 pub fn compute_loss_public(
1870 &self,
1871 prediction: &Array1<f64>,
1872 target: &Array1<f64>,
1873 ) -> Result<f64> {
1874 self.compute_loss(prediction, target)
1875 }
1876
1877 pub fn compute_loss_gradient_public(
1879 &self,
1880 prediction: &Array1<f64>,
1881 target: &Array1<f64>,
1882 ) -> Result<Array1<f64>> {
1883 self.compute_loss_gradient(prediction, target)
1884 }
1885}
1886
1887pub trait QMLLayer: std::fmt::Debug + Send + Sync {
1889 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>>;
1891
1892 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>>;
1894
1895 fn get_parameters(&self) -> Array1<f64>;
1897
1898 fn set_parameters(&mut self, parameters: &Array1<f64>);
1900
1901 fn get_depth(&self) -> usize;
1903
1904 fn get_gate_count(&self) -> usize;
1906
1907 fn get_num_parameters(&self) -> usize;
1909}
1910
1911#[derive(Debug)]
1913pub struct ParameterizedQuantumCircuitLayer {
1914 num_qubits: usize,
1916 config: QMLLayerConfig,
1918 parameters: Array1<f64>,
1920 circuit_structure: Vec<PQCGate>,
1922 simulator: StateVectorSimulator,
1924}
1925
1926impl ParameterizedQuantumCircuitLayer {
1927 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
1929 let mut layer = Self {
1930 num_qubits,
1931 config: config.clone(),
1932 parameters: Array1::zeros(config.num_parameters),
1933 circuit_structure: Vec::new(),
1934 simulator: StateVectorSimulator::new(),
1935 };
1936
1937 layer.initialize_parameters();
1939
1940 layer.build_circuit_structure()?;
1942
1943 Ok(layer)
1944 }
1945
1946 fn initialize_parameters(&mut self) {
1948 let mut rng = thread_rng();
1949 for param in &mut self.parameters {
1950 *param = rng.gen_range(-PI..PI);
1951 }
1952 }
1953
1954 fn build_circuit_structure(&mut self) -> Result<()> {
1956 match self.config.ansatz_type {
1957 AnsatzType::Hardware => self.build_hardware_efficient_ansatz(),
1958 AnsatzType::Layered => self.build_layered_ansatz(),
1959 AnsatzType::BrickWall => self.build_brick_wall_ansatz(),
1960 _ => Err(SimulatorError::InvalidConfiguration(
1961 "Ansatz type not implemented".to_string(),
1962 )),
1963 }
1964 }
1965
1966 fn build_hardware_efficient_ansatz(&mut self) -> Result<()> {
1968 let mut param_idx = 0;
1969
1970 for layer in 0..self.config.depth {
1971 for qubit in 0..self.num_qubits {
1973 for &gate_type in &self.config.rotation_gates {
1974 if param_idx < self.parameters.len() {
1975 self.circuit_structure.push(PQCGate {
1976 gate_type: PQCGateType::SingleQubit(gate_type),
1977 qubits: vec![qubit],
1978 parameter_index: Some(param_idx),
1979 });
1980 param_idx += 1;
1981 }
1982 }
1983 }
1984
1985 self.add_entangling_gates(&mut param_idx);
1987 }
1988
1989 Ok(())
1990 }
1991
1992 fn build_layered_ansatz(&mut self) -> Result<()> {
1994 self.build_hardware_efficient_ansatz()
1996 }
1997
1998 fn build_brick_wall_ansatz(&mut self) -> Result<()> {
2000 let mut param_idx = 0;
2001
2002 for layer in 0..self.config.depth {
2003 let offset = layer % 2;
2005 for i in (offset..self.num_qubits - 1).step_by(2) {
2006 self.circuit_structure.push(PQCGate {
2007 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2008 qubits: vec![i, i + 1],
2009 parameter_index: None,
2010 });
2011 }
2012
2013 for qubit in 0..self.num_qubits {
2015 if param_idx < self.parameters.len() {
2016 self.circuit_structure.push(PQCGate {
2017 gate_type: PQCGateType::SingleQubit(RotationGate::RY),
2018 qubits: vec![qubit],
2019 parameter_index: Some(param_idx),
2020 });
2021 param_idx += 1;
2022 }
2023 }
2024 }
2025
2026 Ok(())
2027 }
2028
2029 fn add_entangling_gates(&mut self, param_idx: &mut usize) {
2031 match self.config.entanglement_pattern {
2032 EntanglementPattern::Linear => {
2033 for i in 0..(self.num_qubits - 1) {
2034 self.circuit_structure.push(PQCGate {
2035 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2036 qubits: vec![i, i + 1],
2037 parameter_index: None,
2038 });
2039 }
2040 }
2041 EntanglementPattern::Circular => {
2042 for i in 0..self.num_qubits {
2043 let next = (i + 1) % self.num_qubits;
2044 self.circuit_structure.push(PQCGate {
2045 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2046 qubits: vec![i, next],
2047 parameter_index: None,
2048 });
2049 }
2050 }
2051 EntanglementPattern::AllToAll => {
2052 for i in 0..self.num_qubits {
2053 for j in (i + 1)..self.num_qubits {
2054 self.circuit_structure.push(PQCGate {
2055 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2056 qubits: vec![i, j],
2057 parameter_index: None,
2058 });
2059 }
2060 }
2061 }
2062 _ => {
2063 for i in 0..(self.num_qubits - 1) {
2065 self.circuit_structure.push(PQCGate {
2066 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2067 qubits: vec![i, i + 1],
2068 parameter_index: None,
2069 });
2070 }
2071 }
2072 }
2073 }
2074}
2075
2076impl QMLLayer for ParameterizedQuantumCircuitLayer {
2077 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2078 let mut state = input.clone();
2079
2080 for gate in &self.circuit_structure {
2082 state = self.apply_gate(&state, gate)?;
2083 }
2084
2085 Ok(state)
2086 }
2087
2088 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2089 Ok(gradient.clone())
2091 }
2092
2093 fn get_parameters(&self) -> Array1<f64> {
2094 self.parameters.clone()
2095 }
2096
2097 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2098 self.parameters = parameters.clone();
2099 }
2100
2101 fn get_depth(&self) -> usize {
2102 self.config.depth
2103 }
2104
2105 fn get_gate_count(&self) -> usize {
2106 self.circuit_structure.len()
2107 }
2108
2109 fn get_num_parameters(&self) -> usize {
2110 self.parameters.len()
2111 }
2112}
2113
2114impl ParameterizedQuantumCircuitLayer {
2115 fn apply_gate(&self, state: &Array1<Complex64>, gate: &PQCGate) -> Result<Array1<Complex64>> {
2117 match &gate.gate_type {
2118 PQCGateType::SingleQubit(rotation_gate) => {
2119 let angle = if let Some(param_idx) = gate.parameter_index {
2120 self.parameters[param_idx]
2121 } else {
2122 0.0
2123 };
2124 self.apply_single_qubit_gate(state, gate.qubits[0], *rotation_gate, angle)
2125 }
2126 PQCGateType::TwoQubit(two_qubit_gate) => {
2127 self.apply_two_qubit_gate(state, gate.qubits[0], gate.qubits[1], *two_qubit_gate)
2128 }
2129 }
2130 }
2131
2132 fn apply_single_qubit_gate(
2134 &self,
2135 state: &Array1<Complex64>,
2136 qubit: usize,
2137 gate_type: RotationGate,
2138 angle: f64,
2139 ) -> Result<Array1<Complex64>> {
2140 let state_size = state.len();
2141 let mut new_state = Array1::zeros(state_size);
2142
2143 match gate_type {
2144 RotationGate::RX => {
2145 let cos_half = (angle / 2.0).cos();
2146 let sin_half = (angle / 2.0).sin();
2147
2148 for i in 0..state_size {
2149 if i & (1 << qubit) == 0 {
2150 let j = i | (1 << qubit);
2151 if j < state_size {
2152 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2153 + Complex64::new(0.0, -sin_half) * state[j];
2154 new_state[j] = Complex64::new(0.0, -sin_half) * state[i]
2155 + Complex64::new(cos_half, 0.0) * state[j];
2156 }
2157 }
2158 }
2159 }
2160 RotationGate::RY => {
2161 let cos_half = (angle / 2.0).cos();
2162 let sin_half = (angle / 2.0).sin();
2163
2164 for i in 0..state_size {
2165 if i & (1 << qubit) == 0 {
2166 let j = i | (1 << qubit);
2167 if j < state_size {
2168 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2169 - Complex64::new(sin_half, 0.0) * state[j];
2170 new_state[j] = Complex64::new(sin_half, 0.0) * state[i]
2171 + Complex64::new(cos_half, 0.0) * state[j];
2172 }
2173 }
2174 }
2175 }
2176 RotationGate::RZ => {
2177 let phase_0 = Complex64::from_polar(1.0, -angle / 2.0);
2178 let phase_1 = Complex64::from_polar(1.0, angle / 2.0);
2179
2180 for i in 0..state_size {
2181 if i & (1 << qubit) == 0 {
2182 new_state[i] = phase_0 * state[i];
2183 } else {
2184 new_state[i] = phase_1 * state[i];
2185 }
2186 }
2187 }
2188 _ => {
2189 return Err(SimulatorError::InvalidGate(
2190 "Gate type not implemented".to_string(),
2191 ))
2192 }
2193 }
2194
2195 Ok(new_state)
2196 }
2197
2198 fn apply_two_qubit_gate(
2200 &self,
2201 state: &Array1<Complex64>,
2202 control: usize,
2203 target: usize,
2204 gate_type: TwoQubitGate,
2205 ) -> Result<Array1<Complex64>> {
2206 let state_size = state.len();
2207 let mut new_state = state.clone();
2208
2209 match gate_type {
2210 TwoQubitGate::CNOT => {
2211 for i in 0..state_size {
2212 if (i & (1 << control)) != 0 {
2213 let j = i ^ (1 << target);
2215 new_state[i] = state[j];
2216 }
2217 }
2218 }
2219 TwoQubitGate::CZ => {
2220 for i in 0..state_size {
2221 if (i & (1 << control)) != 0 && (i & (1 << target)) != 0 {
2222 new_state[i] = -state[i];
2224 }
2225 }
2226 }
2227 TwoQubitGate::SWAP => {
2228 for i in 0..state_size {
2229 let ctrl_bit = (i & (1 << control)) != 0;
2230 let targ_bit = (i & (1 << target)) != 0;
2231 if ctrl_bit != targ_bit {
2232 let j = i ^ (1 << control) ^ (1 << target);
2234 new_state[i] = state[j];
2235 }
2236 }
2237 }
2238 TwoQubitGate::CPhase => {
2239 for i in 0..state_size {
2240 if (i & (1 << control)) != 0 && (i & (1 << target)) != 0 {
2241 new_state[i] = -state[i];
2243 }
2244 }
2245 }
2246 }
2247
2248 Ok(new_state)
2249 }
2250}
2251
2252#[derive(Debug)]
2254pub struct QuantumConvolutionalLayer {
2255 num_qubits: usize,
2257 config: QMLLayerConfig,
2259 parameters: Array1<f64>,
2261 conv_structure: Vec<ConvolutionalFilter>,
2263}
2264
2265impl QuantumConvolutionalLayer {
2266 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2268 let mut layer = Self {
2269 num_qubits,
2270 config: config.clone(),
2271 parameters: Array1::zeros(config.num_parameters),
2272 conv_structure: Vec::new(),
2273 };
2274
2275 layer.initialize_parameters();
2276 layer.build_convolutional_structure()?;
2277
2278 Ok(layer)
2279 }
2280
2281 fn initialize_parameters(&mut self) {
2283 let mut rng = thread_rng();
2284 for param in &mut self.parameters {
2285 *param = rng.gen_range(-PI..PI);
2286 }
2287 }
2288
2289 fn build_convolutional_structure(&mut self) -> Result<()> {
2291 let filter_size = 2; let stride = 1;
2294
2295 let mut param_idx = 0;
2296 for start in (0..=(self.num_qubits - filter_size)).step_by(stride) {
2297 if param_idx + 2 <= self.parameters.len() {
2298 self.conv_structure.push(ConvolutionalFilter {
2299 qubits: vec![start, start + 1],
2300 parameter_indices: vec![param_idx, param_idx + 1],
2301 });
2302 param_idx += 2;
2303 }
2304 }
2305
2306 Ok(())
2307 }
2308}
2309
2310impl QMLLayer for QuantumConvolutionalLayer {
2311 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2312 let mut state = input.clone();
2313
2314 for filter in &self.conv_structure {
2316 state = self.apply_convolutional_filter(&state, filter)?;
2317 }
2318
2319 Ok(state)
2320 }
2321
2322 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2323 Ok(gradient.clone())
2324 }
2325
2326 fn get_parameters(&self) -> Array1<f64> {
2327 self.parameters.clone()
2328 }
2329
2330 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2331 self.parameters = parameters.clone();
2332 }
2333
2334 fn get_depth(&self) -> usize {
2335 self.conv_structure.len()
2336 }
2337
2338 fn get_gate_count(&self) -> usize {
2339 self.conv_structure.len() * 4 }
2341
2342 fn get_num_parameters(&self) -> usize {
2343 self.parameters.len()
2344 }
2345}
2346
2347impl QuantumConvolutionalLayer {
2348 fn apply_convolutional_filter(
2350 &self,
2351 state: &Array1<Complex64>,
2352 filter: &ConvolutionalFilter,
2353 ) -> Result<Array1<Complex64>> {
2354 let mut new_state = state.clone();
2355
2356 let param1 = self.parameters[filter.parameter_indices[0]];
2358 let param2 = self.parameters[filter.parameter_indices[1]];
2359
2360 new_state = self.apply_ry_to_state(&new_state, filter.qubits[0], param1)?;
2362 new_state = self.apply_ry_to_state(&new_state, filter.qubits[1], param2)?;
2363 new_state = self.apply_cnot_to_state(&new_state, filter.qubits[0], filter.qubits[1])?;
2364
2365 Ok(new_state)
2366 }
2367
2368 fn apply_ry_to_state(
2370 &self,
2371 state: &Array1<Complex64>,
2372 qubit: usize,
2373 angle: f64,
2374 ) -> Result<Array1<Complex64>> {
2375 let state_size = state.len();
2376 let mut new_state = Array1::zeros(state_size);
2377
2378 let cos_half = (angle / 2.0).cos();
2379 let sin_half = (angle / 2.0).sin();
2380
2381 for i in 0..state_size {
2382 if i & (1 << qubit) == 0 {
2383 let j = i | (1 << qubit);
2384 if j < state_size {
2385 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2386 - Complex64::new(sin_half, 0.0) * state[j];
2387 new_state[j] = Complex64::new(sin_half, 0.0) * state[i]
2388 + Complex64::new(cos_half, 0.0) * state[j];
2389 }
2390 }
2391 }
2392
2393 Ok(new_state)
2394 }
2395
2396 fn apply_cnot_to_state(
2398 &self,
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 &self,
2529 state: &Array1<Complex64>,
2530 qubit1: usize,
2531 qubit2: usize,
2532 angle: f64,
2533 ) -> Result<Array1<Complex64>> {
2534 let state_size = state.len();
2535 let mut new_state = state.clone();
2536
2537 let cos_val = angle.cos();
2539 let sin_val = angle.sin();
2540
2541 for i in 0..state_size {
2542 if (i & (1 << qubit1)) != 0 && (i & (1 << qubit2)) != 0 {
2543 let phase = Complex64::new(cos_val, sin_val);
2545 new_state[i] *= phase;
2546 }
2547 }
2548
2549 Ok(new_state)
2550 }
2551}
2552
2553#[derive(Debug)]
2555pub struct QuantumLSTMLayer {
2556 num_qubits: usize,
2558 config: QMLLayerConfig,
2560 parameters: Array1<f64>,
2562 lstm_gates: Vec<LSTMGate>,
2564 hidden_state: Option<Array1<Complex64>>,
2566 cell_state: Option<Array1<Complex64>>,
2568}
2569
2570impl QuantumLSTMLayer {
2571 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2573 let mut layer = Self {
2574 num_qubits,
2575 config: config.clone(),
2576 parameters: Array1::zeros(config.num_parameters),
2577 lstm_gates: Vec::new(),
2578 hidden_state: None,
2579 cell_state: None,
2580 };
2581
2582 layer.initialize_parameters();
2583 layer.build_lstm_structure()?;
2584
2585 Ok(layer)
2586 }
2587
2588 fn initialize_parameters(&mut self) {
2590 let mut rng = thread_rng();
2591 for param in &mut self.parameters {
2592 *param = rng.gen_range(-PI..PI);
2593 }
2594 }
2595
2596 fn build_lstm_structure(&mut self) -> Result<()> {
2598 let params_per_gate = self.parameters.len() / 4; self.lstm_gates = vec![
2601 LSTMGate {
2602 gate_type: LSTMGateType::Forget,
2603 parameter_start: 0,
2604 parameter_count: params_per_gate,
2605 },
2606 LSTMGate {
2607 gate_type: LSTMGateType::Input,
2608 parameter_start: params_per_gate,
2609 parameter_count: params_per_gate,
2610 },
2611 LSTMGate {
2612 gate_type: LSTMGateType::Output,
2613 parameter_start: 2 * params_per_gate,
2614 parameter_count: params_per_gate,
2615 },
2616 LSTMGate {
2617 gate_type: LSTMGateType::Candidate,
2618 parameter_start: 3 * params_per_gate,
2619 parameter_count: params_per_gate,
2620 },
2621 ];
2622
2623 Ok(())
2624 }
2625}
2626
2627impl QMLLayer for QuantumLSTMLayer {
2628 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2629 if self.hidden_state.is_none() {
2631 let state_size = 1 << self.num_qubits;
2632 self.hidden_state = Some(Array1::zeros(state_size));
2633 self.cell_state = Some(Array1::zeros(state_size));
2634 self.hidden_state.as_mut().unwrap()[0] = Complex64::new(1.0, 0.0);
2636 self.cell_state.as_mut().unwrap()[0] = Complex64::new(1.0, 0.0);
2637 }
2638
2639 let mut current_state = input.clone();
2640
2641 for gate in &self.lstm_gates {
2643 current_state = self.apply_lstm_gate(¤t_state, gate)?;
2644 }
2645
2646 self.hidden_state = Some(current_state.clone());
2648
2649 Ok(current_state)
2650 }
2651
2652 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2653 Ok(gradient.clone())
2654 }
2655
2656 fn get_parameters(&self) -> Array1<f64> {
2657 self.parameters.clone()
2658 }
2659
2660 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2661 self.parameters = parameters.clone();
2662 }
2663
2664 fn get_depth(&self) -> usize {
2665 self.lstm_gates.len()
2666 }
2667
2668 fn get_gate_count(&self) -> usize {
2669 self.parameters.len() }
2671
2672 fn get_num_parameters(&self) -> usize {
2673 self.parameters.len()
2674 }
2675}
2676
2677impl QuantumLSTMLayer {
2678 fn apply_lstm_gate(
2680 &self,
2681 state: &Array1<Complex64>,
2682 gate: &LSTMGate,
2683 ) -> Result<Array1<Complex64>> {
2684 let mut new_state = state.clone();
2685
2686 for i in 0..gate.parameter_count {
2688 let param_idx = gate.parameter_start + i;
2689 if param_idx < self.parameters.len() {
2690 let angle = self.parameters[param_idx];
2691 let qubit = i % self.num_qubits;
2692
2693 new_state = self.apply_rotation(&new_state, qubit, angle)?;
2695 }
2696 }
2697
2698 Ok(new_state)
2699 }
2700
2701 fn apply_rotation(
2703 &self,
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 pub fn get_lstm_gates(&self) -> &[LSTMGate] {
2731 &self.lstm_gates
2732 }
2733}
2734
2735#[derive(Debug)]
2737pub struct QuantumAttentionLayer {
2738 num_qubits: usize,
2740 config: QMLLayerConfig,
2742 parameters: Array1<f64>,
2744 attention_structure: Vec<AttentionHead>,
2746}
2747
2748impl QuantumAttentionLayer {
2749 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2751 let mut layer = Self {
2752 num_qubits,
2753 config: config.clone(),
2754 parameters: Array1::zeros(config.num_parameters),
2755 attention_structure: Vec::new(),
2756 };
2757
2758 layer.initialize_parameters();
2759 layer.build_attention_structure()?;
2760
2761 Ok(layer)
2762 }
2763
2764 fn initialize_parameters(&mut self) {
2766 let mut rng = thread_rng();
2767 for param in &mut self.parameters {
2768 *param = rng.gen_range(-PI..PI);
2769 }
2770 }
2771
2772 fn build_attention_structure(&mut self) -> Result<()> {
2774 let num_heads = 2; let params_per_head = self.parameters.len() / num_heads;
2776
2777 for head in 0..num_heads {
2778 self.attention_structure.push(AttentionHead {
2779 head_id: head,
2780 parameter_start: head * params_per_head,
2781 parameter_count: params_per_head,
2782 query_qubits: (0..self.num_qubits / 2).collect(),
2783 key_qubits: (self.num_qubits / 2..self.num_qubits).collect(),
2784 });
2785 }
2786
2787 Ok(())
2788 }
2789}
2790
2791impl QMLLayer for QuantumAttentionLayer {
2792 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2793 let mut state = input.clone();
2794
2795 for head in &self.attention_structure {
2797 state = self.apply_attention_head(&state, head)?;
2798 }
2799
2800 Ok(state)
2801 }
2802
2803 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2804 Ok(gradient.clone())
2805 }
2806
2807 fn get_parameters(&self) -> Array1<f64> {
2808 self.parameters.clone()
2809 }
2810
2811 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2812 self.parameters = parameters.clone();
2813 }
2814
2815 fn get_depth(&self) -> usize {
2816 self.attention_structure.len()
2817 }
2818
2819 fn get_gate_count(&self) -> usize {
2820 self.parameters.len()
2821 }
2822
2823 fn get_num_parameters(&self) -> usize {
2824 self.parameters.len()
2825 }
2826}
2827
2828impl QuantumAttentionLayer {
2829 fn apply_attention_head(
2831 &self,
2832 state: &Array1<Complex64>,
2833 head: &AttentionHead,
2834 ) -> Result<Array1<Complex64>> {
2835 let mut new_state = state.clone();
2836
2837 for i in 0..head.parameter_count {
2839 let param_idx = head.parameter_start + i;
2840 if param_idx < self.parameters.len() {
2841 let angle = self.parameters[param_idx];
2842
2843 if i < head.query_qubits.len() && i < head.key_qubits.len() {
2845 let query_qubit = head.query_qubits[i];
2846 let key_qubit = head.key_qubits[i];
2847
2848 new_state =
2849 self.apply_attention_gate(&new_state, query_qubit, key_qubit, angle)?;
2850 }
2851 }
2852 }
2853
2854 Ok(new_state)
2855 }
2856
2857 fn apply_attention_gate(
2859 &self,
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 pub fn get_attention_structure(&self) -> &[AttentionHead] {
2890 &self.attention_structure
2891 }
2892}
2893
2894#[derive(Debug, Clone)]
2896pub struct QMLTrainingState {
2897 pub current_epoch: usize,
2899 pub current_learning_rate: f64,
2901 pub best_validation_loss: f64,
2903 pub patience_counter: usize,
2905 pub training_loss_history: Vec<f64>,
2907 pub validation_loss_history: Vec<f64>,
2909}
2910
2911impl Default for QMLTrainingState {
2912 fn default() -> Self {
2913 Self::new()
2914 }
2915}
2916
2917impl QMLTrainingState {
2918 pub const fn new() -> Self {
2920 Self {
2921 current_epoch: 0,
2922 current_learning_rate: 0.01,
2923 best_validation_loss: f64::INFINITY,
2924 patience_counter: 0,
2925 training_loss_history: Vec::new(),
2926 validation_loss_history: Vec::new(),
2927 }
2928 }
2929}
2930
2931#[derive(Debug, Clone)]
2933pub struct QMLTrainingResult {
2934 pub final_training_loss: f64,
2936 pub final_validation_loss: f64,
2938 pub best_validation_loss: f64,
2940 pub epochs_trained: usize,
2942 pub total_training_time: std::time::Duration,
2944 pub training_metrics: Vec<QMLEpochMetrics>,
2946 pub quantum_advantage_metrics: QuantumAdvantageMetrics,
2948}
2949
2950#[derive(Debug, Clone)]
2952pub struct QMLEpochMetrics {
2953 pub epoch: usize,
2955 pub training_loss: f64,
2957 pub validation_loss: f64,
2959 pub epoch_time: std::time::Duration,
2961 pub learning_rate: f64,
2963}
2964
2965#[derive(Debug, Clone, Serialize, Deserialize)]
2967pub struct QuantumAdvantageMetrics {
2968 pub quantum_volume: f64,
2970 pub classical_simulation_cost: f64,
2972 pub quantum_speedup_factor: f64,
2974 pub circuit_depth: usize,
2976 pub gate_count: usize,
2978 pub entanglement_measure: f64,
2980}
2981
2982#[derive(Debug, Clone)]
2984pub struct QMLStats {
2985 pub forward_passes: usize,
2987 pub backward_passes: usize,
2989 pub total_training_time: std::time::Duration,
2991 pub average_epoch_time: std::time::Duration,
2993 pub peak_memory_usage: usize,
2995 pub num_parameters: usize,
2997}
2998
2999impl Default for QMLStats {
3000 fn default() -> Self {
3001 Self::new()
3002 }
3003}
3004
3005impl QMLStats {
3006 pub const fn new() -> Self {
3008 Self {
3009 forward_passes: 0,
3010 backward_passes: 0,
3011 total_training_time: std::time::Duration::from_secs(0),
3012 average_epoch_time: std::time::Duration::from_secs(0),
3013 peak_memory_usage: 0,
3014 num_parameters: 0,
3015 }
3016 }
3017}
3018
3019#[derive(Debug, Clone)]
3021pub struct PQCGate {
3022 pub gate_type: PQCGateType,
3024 pub qubits: Vec<usize>,
3026 pub parameter_index: Option<usize>,
3028}
3029
3030#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3032pub enum PQCGateType {
3033 SingleQubit(RotationGate),
3035 TwoQubit(TwoQubitGate),
3037}
3038
3039#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3041pub enum TwoQubitGate {
3042 CNOT,
3044 CZ,
3046 SWAP,
3048 CPhase,
3050}
3051
3052#[derive(Debug, Clone)]
3054pub struct ConvolutionalFilter {
3055 pub qubits: Vec<usize>,
3057 pub parameter_indices: Vec<usize>,
3059}
3060
3061#[derive(Debug, Clone)]
3063pub struct DenseConnection {
3064 pub qubit1: usize,
3066 pub qubit2: usize,
3068 pub parameter_index: usize,
3070}
3071
3072#[derive(Debug, Clone)]
3074pub struct LSTMGate {
3075 pub gate_type: LSTMGateType,
3077 pub parameter_start: usize,
3079 pub parameter_count: usize,
3081}
3082
3083#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3085pub enum LSTMGateType {
3086 Forget,
3088 Input,
3090 Output,
3092 Candidate,
3094}
3095
3096#[derive(Debug, Clone)]
3098pub struct AttentionHead {
3099 pub head_id: usize,
3101 pub parameter_start: usize,
3103 pub parameter_count: usize,
3105 pub query_qubits: Vec<usize>,
3107 pub key_qubits: Vec<usize>,
3109}
3110
3111#[derive(Debug, Clone, Serialize, Deserialize)]
3113pub struct QMLBenchmarkResults {
3114 pub training_times: HashMap<String, std::time::Duration>,
3116 pub final_accuracies: HashMap<String, f64>,
3118 pub convergence_rates: HashMap<String, f64>,
3120 pub memory_usage: HashMap<String, usize>,
3122 pub quantum_advantage: HashMap<String, QuantumAdvantageMetrics>,
3124 pub parameter_counts: HashMap<String, usize>,
3126 pub circuit_depths: HashMap<String, usize>,
3128 pub gate_counts: HashMap<String, usize>,
3130}
3131
3132pub struct QMLUtils;
3134
3135impl QMLUtils {
3136 pub fn generate_synthetic_data(
3138 num_samples: usize,
3139 input_dim: usize,
3140 output_dim: usize,
3141 ) -> (Vec<Array1<f64>>, Vec<Array1<f64>>) {
3142 let mut rng = thread_rng();
3143 let mut inputs = Vec::new();
3144 let mut outputs = Vec::new();
3145
3146 for _ in 0..num_samples {
3147 let input: Array1<f64> = Array1::from_vec(
3148 (0..input_dim)
3149 .map(|_| rng.gen_range(-1.0_f64..1.0_f64))
3150 .collect(),
3151 );
3152
3153 let output = Array1::from_vec(
3155 (0..output_dim)
3156 .map(|i| {
3157 if i < input_dim {
3158 input[i].sin() } else {
3160 rng.gen_range(-1.0_f64..1.0_f64)
3161 }
3162 })
3163 .collect(),
3164 );
3165
3166 inputs.push(input);
3167 outputs.push(output);
3168 }
3169
3170 (inputs, outputs)
3171 }
3172
3173 pub fn train_test_split(
3175 inputs: Vec<Array1<f64>>,
3176 outputs: Vec<Array1<f64>>,
3177 test_ratio: f64,
3178 ) -> (
3179 Vec<(Array1<f64>, Array1<f64>)>,
3180 Vec<(Array1<f64>, Array1<f64>)>,
3181 ) {
3182 let total_samples = inputs.len();
3183 let test_samples = ((total_samples as f64) * test_ratio) as usize;
3184 let train_samples = total_samples - test_samples;
3185
3186 let mut combined: Vec<(Array1<f64>, Array1<f64>)> =
3187 inputs.into_iter().zip(outputs).collect();
3188
3189 let mut rng = thread_rng();
3191 for i in (1..combined.len()).rev() {
3192 let j = rng.gen_range(0..=i);
3193 combined.swap(i, j);
3194 }
3195
3196 let (train_data, test_data) = combined.split_at(train_samples);
3197 (train_data.to_vec(), test_data.to_vec())
3198 }
3199
3200 pub fn evaluate_accuracy(
3202 predictions: &[Array1<f64>],
3203 targets: &[Array1<f64>],
3204 threshold: f64,
3205 ) -> f64 {
3206 let mut correct = 0;
3207 let total = predictions.len();
3208
3209 for (pred, target) in predictions.iter().zip(targets.iter()) {
3210 let diff = pred - target;
3211 let mse = diff.iter().map(|x| x * x).sum::<f64>() / diff.len() as f64;
3212 if mse < threshold {
3213 correct += 1;
3214 }
3215 }
3216
3217 correct as f64 / total as f64
3218 }
3219
3220 pub fn compute_circuit_complexity(
3222 num_qubits: usize,
3223 depth: usize,
3224 gate_count: usize,
3225 ) -> HashMap<String, f64> {
3226 let mut metrics = HashMap::new();
3227
3228 let state_space_size = 2.0_f64.powi(num_qubits as i32);
3230 metrics.insert("state_space_size".to_string(), state_space_size);
3231
3232 let circuit_complexity = (depth * gate_count) as f64;
3234 metrics.insert("circuit_complexity".to_string(), circuit_complexity);
3235
3236 let classical_cost = state_space_size * gate_count as f64;
3238 metrics.insert("classical_simulation_cost".to_string(), classical_cost);
3239
3240 let quantum_advantage = classical_cost.log(circuit_complexity);
3242 metrics.insert("quantum_advantage_estimate".to_string(), quantum_advantage);
3243
3244 metrics
3245 }
3246}
3247
3248pub fn benchmark_quantum_ml_layers(config: &QMLConfig) -> Result<QMLBenchmarkResults> {
3250 let mut results = QMLBenchmarkResults {
3251 training_times: HashMap::new(),
3252 final_accuracies: HashMap::new(),
3253 convergence_rates: HashMap::new(),
3254 memory_usage: HashMap::new(),
3255 quantum_advantage: HashMap::new(),
3256 parameter_counts: HashMap::new(),
3257 circuit_depths: HashMap::new(),
3258 gate_counts: HashMap::new(),
3259 };
3260
3261 let (inputs, outputs) =
3263 QMLUtils::generate_synthetic_data(100, config.num_qubits, config.num_qubits);
3264 let (train_data, val_data) = QMLUtils::train_test_split(inputs, outputs, 0.2);
3265
3266 let architectures = vec![
3268 QMLArchitectureType::VariationalQuantumCircuit,
3269 QMLArchitectureType::QuantumConvolutionalNN,
3270 ];
3272
3273 for architecture in architectures {
3274 let arch_name = format!("{architecture:?}");
3275
3276 let mut arch_config = config.clone();
3278 arch_config.architecture_type = architecture;
3279
3280 let start_time = std::time::Instant::now();
3282 let mut framework = QuantumMLFramework::new(arch_config)?;
3283
3284 let training_result = framework.train(&train_data, Some(&val_data))?;
3285 let training_time = start_time.elapsed();
3286
3287 let final_accuracy = framework.evaluate(&val_data)?;
3289
3290 results
3292 .training_times
3293 .insert(arch_name.clone(), training_time);
3294 results
3295 .final_accuracies
3296 .insert(arch_name.clone(), 1.0 / (1.0 + final_accuracy)); results.convergence_rates.insert(
3298 arch_name.clone(),
3299 training_result.epochs_trained as f64 / config.training_config.epochs as f64,
3300 );
3301 results
3302 .memory_usage
3303 .insert(arch_name.clone(), framework.get_stats().peak_memory_usage);
3304 results
3305 .quantum_advantage
3306 .insert(arch_name.clone(), training_result.quantum_advantage_metrics);
3307 results.parameter_counts.insert(
3308 arch_name.clone(),
3309 framework
3310 .layers
3311 .iter()
3312 .map(|l| l.get_num_parameters())
3313 .sum(),
3314 );
3315 results.circuit_depths.insert(
3316 arch_name.clone(),
3317 framework.layers.iter().map(|l| l.get_depth()).sum(),
3318 );
3319 results.gate_counts.insert(
3320 arch_name.clone(),
3321 framework.layers.iter().map(|l| l.get_gate_count()).sum(),
3322 );
3323 }
3324
3325 Ok(results)
3326}