1use ndarray::Array1;
9use num_complex::Complex64;
10use rand::{thread_rng, Rng};
11use scirs2_core::parallel_ops::*;
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14use std::f64::consts::PI;
15
16use crate::error::{Result, SimulatorError};
17use crate::scirs2_integration::SciRS2Backend;
18use crate::statevector::StateVectorSimulator;
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct QMLConfig {
23 pub num_qubits: usize,
25 pub architecture_type: QMLArchitectureType,
27 pub layer_configs: Vec<QMLLayerConfig>,
29 pub training_config: QMLTrainingConfig,
31 pub hardware_optimization: HardwareOptimizationConfig,
33 pub classical_preprocessing: ClassicalPreprocessingConfig,
35 pub hybrid_training: HybridTrainingConfig,
37 pub quantum_advantage_analysis: bool,
39 pub noise_aware_training: NoiseAwareTrainingConfig,
41 pub performance_optimization: PerformanceOptimizationConfig,
43}
44
45impl Default for QMLConfig {
46 fn default() -> Self {
47 Self {
48 num_qubits: 8,
49 architecture_type: QMLArchitectureType::VariationalQuantumCircuit,
50 layer_configs: vec![QMLLayerConfig {
51 layer_type: QMLLayerType::ParameterizedQuantumCircuit,
52 num_parameters: 16,
53 ansatz_type: AnsatzType::Hardware,
54 entanglement_pattern: EntanglementPattern::Linear,
55 rotation_gates: vec![RotationGate::RY, RotationGate::RZ],
56 depth: 4,
57 enable_gradient_computation: true,
58 }],
59 training_config: QMLTrainingConfig::default(),
60 hardware_optimization: HardwareOptimizationConfig::default(),
61 classical_preprocessing: ClassicalPreprocessingConfig::default(),
62 hybrid_training: HybridTrainingConfig::default(),
63 quantum_advantage_analysis: true,
64 noise_aware_training: NoiseAwareTrainingConfig::default(),
65 performance_optimization: PerformanceOptimizationConfig::default(),
66 }
67 }
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
72pub enum QMLArchitectureType {
73 VariationalQuantumCircuit,
75 QuantumConvolutionalNN,
77 QuantumRecurrentNN,
79 QuantumGraphNN,
81 QuantumAttentionNetwork,
83 QuantumTransformer,
85 HybridClassicalQuantum,
87 QuantumBoltzmannMachine,
89 QuantumGAN,
91 QuantumAutoencoder,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct QMLLayerConfig {
98 pub layer_type: QMLLayerType,
100 pub num_parameters: usize,
102 pub ansatz_type: AnsatzType,
104 pub entanglement_pattern: EntanglementPattern,
106 pub rotation_gates: Vec<RotationGate>,
108 pub depth: usize,
110 pub enable_gradient_computation: bool,
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
116pub enum QMLLayerType {
117 ParameterizedQuantumCircuit,
119 QuantumConvolutional,
121 QuantumPooling,
123 QuantumDense,
125 QuantumLSTM,
127 QuantumGRU,
129 QuantumAttention,
131 QuantumDropout,
133 QuantumBatchNorm,
135 DataReUpload,
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
141pub enum AnsatzType {
142 Hardware,
144 ProblemSpecific,
146 AllToAll,
148 Layered,
150 Alternating,
152 BrickWall,
154 Tree,
156 Custom,
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
162pub enum EntanglementPattern {
163 Linear,
165 Circular,
167 AllToAll,
169 Star,
171 Grid,
173 Random,
175 Block,
177 Custom,
179}
180
181#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
183pub enum RotationGate {
184 RX,
186 RY,
188 RZ,
190 U3,
192 Phase,
194}
195
196#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct QMLTrainingConfig {
199 pub algorithm: QMLTrainingAlgorithm,
201 pub learning_rate: f64,
203 pub epochs: usize,
205 pub batch_size: usize,
207 pub gradient_method: GradientMethod,
209 pub optimizer: OptimizerType,
211 pub regularization: RegularizationConfig,
213 pub early_stopping: EarlyStoppingConfig,
215 pub lr_schedule: LearningRateSchedule,
217}
218
219impl Default for QMLTrainingConfig {
220 fn default() -> Self {
221 Self {
222 algorithm: QMLTrainingAlgorithm::ParameterShift,
223 learning_rate: 0.01,
224 epochs: 100,
225 batch_size: 32,
226 gradient_method: GradientMethod::ParameterShift,
227 optimizer: OptimizerType::Adam,
228 regularization: RegularizationConfig::default(),
229 early_stopping: EarlyStoppingConfig::default(),
230 lr_schedule: LearningRateSchedule::Constant,
231 }
232 }
233}
234
235#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
237pub enum QMLTrainingAlgorithm {
238 ParameterShift,
240 FiniteDifference,
242 QuantumNaturalGradient,
244 SPSA,
246 QAOA,
248 VQE,
250 Rotosolve,
252 HybridTraining,
254}
255
256#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
258pub enum GradientMethod {
259 ParameterShift,
261 FiniteDifference,
263 Adjoint,
265 Backpropagation,
267 QuantumFisherInformation,
269}
270
271#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
273pub enum OptimizerType {
274 SGD,
276 Adam,
278 AdaGrad,
280 RMSprop,
282 Momentum,
284 LBFGS,
286 QuantumNaturalGradient,
288 SPSA,
290}
291
292#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct RegularizationConfig {
295 pub l1_strength: f64,
297 pub l2_strength: f64,
299 pub dropout_prob: f64,
301 pub parameter_bounds: Option<(f64, f64)>,
303 pub enable_clipping: bool,
305 pub gradient_clip_threshold: f64,
307}
308
309impl Default for RegularizationConfig {
310 fn default() -> Self {
311 Self {
312 l1_strength: 0.0,
313 l2_strength: 0.001,
314 dropout_prob: 0.1,
315 parameter_bounds: Some((-PI, PI)),
316 enable_clipping: true,
317 gradient_clip_threshold: 1.0,
318 }
319 }
320}
321
322#[derive(Debug, Clone, Serialize, Deserialize)]
324pub struct EarlyStoppingConfig {
325 pub enabled: bool,
327 pub patience: usize,
329 pub min_delta: f64,
331 pub monitor_metric: String,
333 pub mode_max: bool,
335}
336
337impl Default for EarlyStoppingConfig {
338 fn default() -> Self {
339 Self {
340 enabled: true,
341 patience: 10,
342 min_delta: 1e-6,
343 monitor_metric: "val_loss".to_string(),
344 mode_max: false,
345 }
346 }
347}
348
349#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
351pub enum LearningRateSchedule {
352 Constant,
354 ExponentialDecay,
356 StepDecay,
358 CosineAnnealing,
360 WarmRestart,
362 ReduceOnPlateau,
364}
365
366#[derive(Debug, Clone, Serialize, Deserialize)]
368pub struct HardwareOptimizationConfig {
369 pub target_hardware: QuantumHardwareTarget,
371 pub minimize_gate_count: bool,
373 pub minimize_depth: bool,
375 pub noise_aware: bool,
377 pub connectivity_constraints: ConnectivityConstraints,
379 pub gate_fidelities: HashMap<String, f64>,
381 pub enable_parallelization: bool,
383 pub optimization_level: HardwareOptimizationLevel,
385}
386
387impl Default for HardwareOptimizationConfig {
388 fn default() -> Self {
389 let mut gate_fidelities = HashMap::new();
390 gate_fidelities.insert("single_qubit".to_string(), 0.999);
391 gate_fidelities.insert("two_qubit".to_string(), 0.99);
392
393 Self {
394 target_hardware: QuantumHardwareTarget::Simulator,
395 minimize_gate_count: true,
396 minimize_depth: true,
397 noise_aware: false,
398 connectivity_constraints: ConnectivityConstraints::AllToAll,
399 gate_fidelities,
400 enable_parallelization: true,
401 optimization_level: HardwareOptimizationLevel::Medium,
402 }
403 }
404}
405
406#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
408pub enum QuantumHardwareTarget {
409 Simulator,
411 IBM,
413 Google,
415 IonQ,
417 Rigetti,
419 Quantinuum,
421 Xanadu,
423 Custom,
425}
426
427#[derive(Debug, Clone, Serialize, Deserialize)]
429pub enum ConnectivityConstraints {
430 AllToAll,
432 Linear,
434 Grid(usize, usize), Custom(Vec<(usize, usize)>), HeavyHex,
440 Square,
442}
443
444#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
446pub enum HardwareOptimizationLevel {
447 Basic,
449 Medium,
451 Aggressive,
453 Maximum,
455}
456
457#[derive(Debug, Clone, Serialize, Deserialize)]
459pub struct ClassicalPreprocessingConfig {
460 pub feature_scaling: bool,
462 pub scaling_method: ScalingMethod,
464 pub enable_pca: bool,
466 pub pca_components: Option<usize>,
468 pub encoding_method: DataEncodingMethod,
470 pub feature_selection: FeatureSelectionConfig,
472}
473
474impl Default for ClassicalPreprocessingConfig {
475 fn default() -> Self {
476 Self {
477 feature_scaling: true,
478 scaling_method: ScalingMethod::StandardScaler,
479 enable_pca: false,
480 pca_components: None,
481 encoding_method: DataEncodingMethod::Amplitude,
482 feature_selection: FeatureSelectionConfig::default(),
483 }
484 }
485}
486
487#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
489pub enum ScalingMethod {
490 StandardScaler,
492 MinMaxScaler,
494 RobustScaler,
496 QuantileUniform,
498 PowerTransformer,
500}
501
502#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
504pub enum DataEncodingMethod {
505 Amplitude,
507 Angle,
509 Basis,
511 QuantumFeatureMap,
513 IQP,
515 PauliFeatureMap,
517 DataReUpload,
519}
520
521#[derive(Debug, Clone, Serialize, Deserialize)]
523pub struct FeatureSelectionConfig {
524 pub enabled: bool,
526 pub method: FeatureSelectionMethod,
528 pub num_features: Option<usize>,
530 pub threshold: f64,
532}
533
534impl Default for FeatureSelectionConfig {
535 fn default() -> Self {
536 Self {
537 enabled: false,
538 method: FeatureSelectionMethod::VarianceThreshold,
539 num_features: None,
540 threshold: 0.0,
541 }
542 }
543}
544
545#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
547pub enum FeatureSelectionMethod {
548 VarianceThreshold,
550 UnivariateSelection,
552 RecursiveFeatureElimination,
554 L1Based,
556 TreeBased,
558 QuantumFeatureImportance,
560}
561
562#[derive(Debug, Clone, Serialize, Deserialize)]
564pub struct HybridTrainingConfig {
565 pub enabled: bool,
567 pub classical_architecture: ClassicalArchitecture,
569 pub interface_config: QuantumClassicalInterface,
571 pub alternating_schedule: AlternatingSchedule,
573 pub gradient_flow: GradientFlowConfig,
575}
576
577impl Default for HybridTrainingConfig {
578 fn default() -> Self {
579 Self {
580 enabled: false,
581 classical_architecture: ClassicalArchitecture::MLP,
582 interface_config: QuantumClassicalInterface::Expectation,
583 alternating_schedule: AlternatingSchedule::Simultaneous,
584 gradient_flow: GradientFlowConfig::default(),
585 }
586 }
587}
588
589#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
591pub enum ClassicalArchitecture {
592 MLP,
594 CNN,
596 RNN,
598 LSTM,
600 Transformer,
602 ResNet,
604 Custom,
606}
607
608#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
610pub enum QuantumClassicalInterface {
611 Expectation,
613 Sampling,
615 StateTomography,
617 ProcessTomography,
619 ShadowTomography,
621}
622
623#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
625pub enum AlternatingSchedule {
626 Simultaneous,
628 Alternating,
630 ClassicalFirst,
632 QuantumFirst,
634 Custom,
636}
637
638#[derive(Debug, Clone, Serialize, Deserialize)]
640pub struct GradientFlowConfig {
641 pub classical_to_quantum: bool,
643 pub quantum_to_classical: bool,
645 pub gradient_scaling: f64,
647 pub enable_clipping: bool,
649 pub accumulation_steps: usize,
651}
652
653impl Default for GradientFlowConfig {
654 fn default() -> Self {
655 Self {
656 classical_to_quantum: true,
657 quantum_to_classical: true,
658 gradient_scaling: 1.0,
659 enable_clipping: true,
660 accumulation_steps: 1,
661 }
662 }
663}
664
665#[derive(Debug, Clone, Serialize, Deserialize)]
667pub struct NoiseAwareTrainingConfig {
668 pub enabled: bool,
670 pub noise_parameters: NoiseParameters,
672 pub error_mitigation: ErrorMitigationConfig,
674 pub noise_characterization: NoiseCharacterizationConfig,
676 pub robust_training: RobustTrainingConfig,
678}
679
680impl Default for NoiseAwareTrainingConfig {
681 fn default() -> Self {
682 Self {
683 enabled: false,
684 noise_parameters: NoiseParameters::default(),
685 error_mitigation: ErrorMitigationConfig::default(),
686 noise_characterization: NoiseCharacterizationConfig::default(),
687 robust_training: RobustTrainingConfig::default(),
688 }
689 }
690}
691
692#[derive(Debug, Clone, Serialize, Deserialize)]
694pub struct NoiseParameters {
695 pub single_qubit_error: f64,
697 pub two_qubit_error: f64,
699 pub measurement_error: f64,
701 pub coherence_times: (f64, f64),
703 pub gate_times: HashMap<String, f64>,
705}
706
707impl Default for NoiseParameters {
708 fn default() -> Self {
709 let mut gate_times = HashMap::new();
710 gate_times.insert("single_qubit".to_string(), 50e-9); gate_times.insert("two_qubit".to_string(), 200e-9); Self {
714 single_qubit_error: 0.001,
715 two_qubit_error: 0.01,
716 measurement_error: 0.01,
717 coherence_times: (50e-6, 100e-6), gate_times,
719 }
720 }
721}
722
723#[derive(Debug, Clone, Serialize, Deserialize)]
725pub struct ErrorMitigationConfig {
726 pub zero_noise_extrapolation: bool,
728 pub readout_error_mitigation: bool,
730 pub symmetry_verification: bool,
732 pub virtual_distillation: VirtualDistillationConfig,
734 pub quantum_error_correction: bool,
736}
737
738impl Default for ErrorMitigationConfig {
739 fn default() -> Self {
740 Self {
741 zero_noise_extrapolation: false,
742 readout_error_mitigation: false,
743 symmetry_verification: false,
744 virtual_distillation: VirtualDistillationConfig::default(),
745 quantum_error_correction: false,
746 }
747 }
748}
749
750#[derive(Debug, Clone, Serialize, Deserialize)]
752pub struct VirtualDistillationConfig {
753 pub enabled: bool,
755 pub num_copies: usize,
757 pub protocol: DistillationProtocol,
759}
760
761impl Default for VirtualDistillationConfig {
762 fn default() -> Self {
763 Self {
764 enabled: false,
765 num_copies: 2,
766 protocol: DistillationProtocol::Standard,
767 }
768 }
769}
770
771#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
773pub enum DistillationProtocol {
774 Standard,
776 Improved,
778 QuantumAdvantage,
780}
781
782#[derive(Debug, Clone, Serialize, Deserialize)]
784pub struct NoiseCharacterizationConfig {
785 pub enabled: bool,
787 pub method: NoiseCharacterizationMethod,
789 pub benchmarking: BenchmarkingProtocols,
791 pub calibration_frequency: CalibrationFrequency,
793}
794
795impl Default for NoiseCharacterizationConfig {
796 fn default() -> Self {
797 Self {
798 enabled: false,
799 method: NoiseCharacterizationMethod::ProcessTomography,
800 benchmarking: BenchmarkingProtocols::default(),
801 calibration_frequency: CalibrationFrequency::Daily,
802 }
803 }
804}
805
806#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
808pub enum NoiseCharacterizationMethod {
809 ProcessTomography,
811 RandomizedBenchmarking,
813 GateSetTomography,
815 QuantumDetectorTomography,
817 CrossEntropyBenchmarking,
819}
820
821#[derive(Debug, Clone, Serialize, Deserialize)]
823pub struct BenchmarkingProtocols {
824 pub randomized_benchmarking: bool,
826 pub quantum_volume: bool,
828 pub cross_entropy_benchmarking: bool,
830 pub mirror_benchmarking: bool,
832}
833
834impl Default for BenchmarkingProtocols {
835 fn default() -> Self {
836 Self {
837 randomized_benchmarking: true,
838 quantum_volume: false,
839 cross_entropy_benchmarking: false,
840 mirror_benchmarking: false,
841 }
842 }
843}
844
845#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
847pub enum CalibrationFrequency {
848 RealTime,
850 Hourly,
852 Daily,
854 Weekly,
856 Manual,
858}
859
860#[derive(Debug, Clone, Serialize, Deserialize)]
862pub struct RobustTrainingConfig {
863 pub enabled: bool,
865 pub noise_injection: NoiseInjectionConfig,
867 pub adversarial_training: AdversarialTrainingConfig,
869 pub ensemble_methods: EnsembleMethodsConfig,
871}
872
873impl Default for RobustTrainingConfig {
874 fn default() -> Self {
875 Self {
876 enabled: false,
877 noise_injection: NoiseInjectionConfig::default(),
878 adversarial_training: AdversarialTrainingConfig::default(),
879 ensemble_methods: EnsembleMethodsConfig::default(),
880 }
881 }
882}
883
884#[derive(Debug, Clone, Serialize, Deserialize)]
886pub struct NoiseInjectionConfig {
887 pub enabled: bool,
889 pub injection_probability: f64,
891 pub noise_strength: f64,
893 pub noise_type: NoiseType,
895}
896
897impl Default for NoiseInjectionConfig {
898 fn default() -> Self {
899 Self {
900 enabled: false,
901 injection_probability: 0.1,
902 noise_strength: 0.01,
903 noise_type: NoiseType::Depolarizing,
904 }
905 }
906}
907
908#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
910pub enum NoiseType {
911 Depolarizing,
913 AmplitudeDamping,
915 PhaseDamping,
917 BitFlip,
919 PhaseFlip,
921 Pauli,
923}
924
925#[derive(Debug, Clone, Serialize, Deserialize)]
927pub struct AdversarialTrainingConfig {
928 pub enabled: bool,
930 pub attack_strength: f64,
932 pub attack_method: AdversarialAttackMethod,
934 pub defense_method: AdversarialDefenseMethod,
936}
937
938impl Default for AdversarialTrainingConfig {
939 fn default() -> Self {
940 Self {
941 enabled: false,
942 attack_strength: 0.01,
943 attack_method: AdversarialAttackMethod::FGSM,
944 defense_method: AdversarialDefenseMethod::AdversarialTraining,
945 }
946 }
947}
948
949#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
951pub enum AdversarialAttackMethod {
952 FGSM,
954 PGD,
956 CarliniWagner,
958 QuantumAdversarial,
960}
961
962#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
964pub enum AdversarialDefenseMethod {
965 AdversarialTraining,
967 DefensiveDistillation,
969 CertifiedDefenses,
971 QuantumErrorCorrection,
973}
974
975#[derive(Debug, Clone, Serialize, Deserialize)]
977pub struct EnsembleMethodsConfig {
978 pub enabled: bool,
980 pub num_ensemble: usize,
982 pub ensemble_method: EnsembleMethod,
984 pub voting_strategy: VotingStrategy,
986}
987
988impl Default for EnsembleMethodsConfig {
989 fn default() -> Self {
990 Self {
991 enabled: false,
992 num_ensemble: 5,
993 ensemble_method: EnsembleMethod::Bagging,
994 voting_strategy: VotingStrategy::MajorityVoting,
995 }
996 }
997}
998
999#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1001pub enum EnsembleMethod {
1002 Bagging,
1004 Boosting,
1006 RandomForest,
1008 QuantumEnsemble,
1010}
1011
1012#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1014pub enum VotingStrategy {
1015 MajorityVoting,
1017 WeightedVoting,
1019 SoftVoting,
1021 QuantumVoting,
1023}
1024
1025#[derive(Debug, Clone, Serialize, Deserialize)]
1027pub struct PerformanceOptimizationConfig {
1028 pub enabled: bool,
1030 pub memory_optimization: MemoryOptimizationConfig,
1032 pub computation_optimization: ComputationOptimizationConfig,
1034 pub parallelization: ParallelizationConfig,
1036 pub caching: CachingConfig,
1038}
1039
1040impl Default for PerformanceOptimizationConfig {
1041 fn default() -> Self {
1042 Self {
1043 enabled: true,
1044 memory_optimization: MemoryOptimizationConfig::default(),
1045 computation_optimization: ComputationOptimizationConfig::default(),
1046 parallelization: ParallelizationConfig::default(),
1047 caching: CachingConfig::default(),
1048 }
1049 }
1050}
1051
1052#[derive(Debug, Clone, Serialize, Deserialize)]
1054pub struct MemoryOptimizationConfig {
1055 pub enabled: bool,
1057 pub memory_mapping: bool,
1059 pub gradient_checkpointing: bool,
1061 pub memory_pool_size: Option<usize>,
1063}
1064
1065impl Default for MemoryOptimizationConfig {
1066 fn default() -> Self {
1067 Self {
1068 enabled: true,
1069 memory_mapping: false,
1070 gradient_checkpointing: false,
1071 memory_pool_size: None,
1072 }
1073 }
1074}
1075
1076#[derive(Debug, Clone, Serialize, Deserialize)]
1078pub struct ComputationOptimizationConfig {
1079 pub enabled: bool,
1081 pub mixed_precision: bool,
1083 pub simd_optimization: bool,
1085 pub jit_compilation: bool,
1087}
1088
1089impl Default for ComputationOptimizationConfig {
1090 fn default() -> Self {
1091 Self {
1092 enabled: true,
1093 mixed_precision: false,
1094 simd_optimization: true,
1095 jit_compilation: false,
1096 }
1097 }
1098}
1099
1100#[derive(Debug, Clone, Serialize, Deserialize)]
1102pub struct ParallelizationConfig {
1103 pub enabled: bool,
1105 pub num_threads: Option<usize>,
1107 pub data_parallelism: bool,
1109 pub model_parallelism: bool,
1111 pub pipeline_parallelism: bool,
1113}
1114
1115impl Default for ParallelizationConfig {
1116 fn default() -> Self {
1117 Self {
1118 enabled: true,
1119 num_threads: None,
1120 data_parallelism: true,
1121 model_parallelism: false,
1122 pipeline_parallelism: false,
1123 }
1124 }
1125}
1126
1127#[derive(Debug, Clone, Serialize, Deserialize)]
1129pub struct CachingConfig {
1130 pub enabled: bool,
1132 pub cache_size: usize,
1134 pub cache_gradients: bool,
1136 pub cache_intermediate: bool,
1138}
1139
1140impl Default for CachingConfig {
1141 fn default() -> Self {
1142 Self {
1143 enabled: true,
1144 cache_size: 1000,
1145 cache_gradients: true,
1146 cache_intermediate: false,
1147 }
1148 }
1149}
1150
1151#[derive(Debug)]
1153pub struct QuantumMLFramework {
1154 config: QMLConfig,
1156 layers: Vec<Box<dyn QMLLayer>>,
1158 training_state: QMLTrainingState,
1160 backend: Option<SciRS2Backend>,
1162 stats: QMLStats,
1164 training_history: Vec<QMLTrainingResult>,
1166}
1167
1168impl QuantumMLFramework {
1169 pub fn new(config: QMLConfig) -> Result<Self> {
1171 let mut framework = Self {
1172 config: config.clone(),
1173 layers: Vec::new(),
1174 training_state: QMLTrainingState::new(),
1175 backend: None,
1176 stats: QMLStats::new(),
1177 training_history: Vec::new(),
1178 };
1179
1180 framework.initialize_layers()?;
1182
1183 let backend = SciRS2Backend::new();
1185 if backend.is_available() {
1186 framework.backend = Some(backend);
1187 }
1188
1189 Ok(framework)
1190 }
1191
1192 fn initialize_layers(&mut self) -> Result<()> {
1194 for layer_config in &self.config.layer_configs {
1195 let layer = self.create_layer(layer_config)?;
1196 self.layers.push(layer);
1197 }
1198 Ok(())
1199 }
1200
1201 fn create_layer(&self, config: &QMLLayerConfig) -> Result<Box<dyn QMLLayer>> {
1203 match config.layer_type {
1204 QMLLayerType::ParameterizedQuantumCircuit => Ok(Box::new(
1205 ParameterizedQuantumCircuitLayer::new(self.config.num_qubits, config.clone())?,
1206 )),
1207 QMLLayerType::QuantumConvolutional => Ok(Box::new(QuantumConvolutionalLayer::new(
1208 self.config.num_qubits,
1209 config.clone(),
1210 )?)),
1211 QMLLayerType::QuantumDense => Ok(Box::new(QuantumDenseLayer::new(
1212 self.config.num_qubits,
1213 config.clone(),
1214 )?)),
1215 QMLLayerType::QuantumLSTM => Ok(Box::new(QuantumLSTMLayer::new(
1216 self.config.num_qubits,
1217 config.clone(),
1218 )?)),
1219 QMLLayerType::QuantumAttention => Ok(Box::new(QuantumAttentionLayer::new(
1220 self.config.num_qubits,
1221 config.clone(),
1222 )?)),
1223 _ => Err(SimulatorError::InvalidConfiguration(format!(
1224 "Layer type {:?} not yet implemented",
1225 config.layer_type
1226 ))),
1227 }
1228 }
1229
1230 pub fn forward(&mut self, input: &Array1<f64>) -> Result<Array1<f64>> {
1232 let mut current_state = self.encode_input(input)?;
1233
1234 for layer in &mut self.layers {
1236 current_state = layer.forward(¤t_state)?;
1237 }
1238
1239 let output = self.decode_output(¤t_state)?;
1241
1242 self.stats.forward_passes += 1;
1244
1245 Ok(output)
1246 }
1247
1248 pub fn backward(&mut self, loss_gradient: &Array1<f64>) -> Result<Array1<f64>> {
1250 let mut grad = loss_gradient.clone();
1251
1252 for layer in self.layers.iter_mut().rev() {
1254 grad = layer.backward(&grad)?;
1255 }
1256
1257 self.stats.backward_passes += 1;
1259
1260 Ok(grad)
1261 }
1262
1263 pub fn train(
1265 &mut self,
1266 training_data: &[(Array1<f64>, Array1<f64>)],
1267 validation_data: Option<&[(Array1<f64>, Array1<f64>)]>,
1268 ) -> Result<QMLTrainingResult> {
1269 let mut best_validation_loss = f64::INFINITY;
1270 let mut patience_counter = 0;
1271 let mut training_metrics = Vec::new();
1272
1273 let training_start = std::time::Instant::now();
1274
1275 for epoch in 0..self.config.training_config.epochs {
1276 let epoch_start = std::time::Instant::now();
1277
1278 let mut epoch_loss = 0.0;
1280 let mut num_batches = 0;
1281
1282 for batch in training_data.chunks(self.config.training_config.batch_size) {
1283 let batch_loss = self.train_batch(batch)?;
1284 epoch_loss += batch_loss;
1285 num_batches += 1;
1286 }
1287
1288 epoch_loss /= num_batches as f64;
1289
1290 let validation_loss = if let Some(val_data) = validation_data {
1292 self.evaluate(val_data)?
1293 } else {
1294 epoch_loss
1295 };
1296
1297 let epoch_time = epoch_start.elapsed();
1298
1299 let metrics = QMLEpochMetrics {
1300 epoch,
1301 training_loss: epoch_loss,
1302 validation_loss,
1303 epoch_time,
1304 learning_rate: self.get_current_learning_rate(epoch),
1305 };
1306
1307 training_metrics.push(metrics.clone());
1308
1309 if self.config.training_config.early_stopping.enabled {
1311 if validation_loss
1312 < best_validation_loss - self.config.training_config.early_stopping.min_delta
1313 {
1314 best_validation_loss = validation_loss;
1315 patience_counter = 0;
1316 } else {
1317 patience_counter += 1;
1318 if patience_counter >= self.config.training_config.early_stopping.patience {
1319 println!("Early stopping triggered at epoch {}", epoch);
1320 break;
1321 }
1322 }
1323 }
1324
1325 self.update_learning_rate(epoch, validation_loss);
1327
1328 if epoch % 10 == 0 {
1330 println!(
1331 "Epoch {}: train_loss={:.6}, val_loss={:.6}, time={:.2}s",
1332 epoch,
1333 epoch_loss,
1334 validation_loss,
1335 epoch_time.as_secs_f64()
1336 );
1337 }
1338 }
1339
1340 let total_training_time = training_start.elapsed();
1341
1342 let result = QMLTrainingResult {
1343 final_training_loss: training_metrics
1344 .last()
1345 .map(|m| m.training_loss)
1346 .unwrap_or(0.0),
1347 final_validation_loss: training_metrics
1348 .last()
1349 .map(|m| m.validation_loss)
1350 .unwrap_or(0.0),
1351 best_validation_loss,
1352 epochs_trained: training_metrics.len(),
1353 total_training_time,
1354 training_metrics,
1355 quantum_advantage_metrics: self.compute_quantum_advantage_metrics()?,
1356 };
1357
1358 self.training_history.push(result.clone());
1359
1360 Ok(result)
1361 }
1362
1363 fn train_batch(&mut self, batch: &[(Array1<f64>, Array1<f64>)]) -> Result<f64> {
1365 let mut total_loss = 0.0;
1366 let mut total_gradients: Vec<Array1<f64>> =
1367 (0..self.layers.len()).map(|_| Array1::zeros(0)).collect();
1368
1369 for (input, target) in batch {
1370 let prediction = self.forward(input)?;
1372
1373 let loss = self.compute_loss(&prediction, target)?;
1375 total_loss += loss;
1376
1377 let loss_gradient = self.compute_loss_gradient(&prediction, target)?;
1379
1380 let gradients = self.compute_gradients(&loss_gradient)?;
1382
1383 for (i, grad) in gradients.iter().enumerate() {
1385 if total_gradients[i].len() == 0 {
1386 total_gradients[i] = grad.clone();
1387 } else {
1388 total_gradients[i] += grad;
1389 }
1390 }
1391 }
1392
1393 let batch_size = batch.len() as f64;
1395 for grad in &mut total_gradients {
1396 *grad /= batch_size;
1397 }
1398
1399 self.apply_gradients(&total_gradients)?;
1401
1402 Ok(total_loss / batch_size)
1403 }
1404
1405 pub fn evaluate(&mut self, data: &[(Array1<f64>, Array1<f64>)]) -> Result<f64> {
1407 let mut total_loss = 0.0;
1408
1409 for (input, target) in data {
1410 let prediction = self.forward(input)?;
1411 let loss = self.compute_loss(&prediction, target)?;
1412 total_loss += loss;
1413 }
1414
1415 Ok(total_loss / data.len() as f64)
1416 }
1417
1418 fn encode_input(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1420 match self.config.classical_preprocessing.encoding_method {
1421 DataEncodingMethod::Amplitude => self.encode_amplitude(input),
1422 DataEncodingMethod::Angle => self.encode_angle(input),
1423 DataEncodingMethod::Basis => self.encode_basis(input),
1424 DataEncodingMethod::QuantumFeatureMap => self.encode_quantum_feature_map(input),
1425 _ => Err(SimulatorError::InvalidConfiguration(
1426 "Encoding method not implemented".to_string(),
1427 )),
1428 }
1429 }
1430
1431 fn encode_amplitude(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1433 let n_qubits = self.config.num_qubits;
1434 let state_size = 1 << n_qubits;
1435 let mut state = Array1::zeros(state_size);
1436
1437 let norm = input.iter().map(|x| x * x).sum::<f64>().sqrt();
1439 if norm == 0.0 {
1440 return Err(SimulatorError::InvalidState("Zero input norm".to_string()));
1441 }
1442
1443 for (i, &val) in input.iter().enumerate() {
1445 if i < state_size {
1446 state[i] = Complex64::new(val / norm, 0.0);
1447 }
1448 }
1449
1450 Ok(state)
1451 }
1452
1453 fn encode_angle(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1455 let n_qubits = self.config.num_qubits;
1456 let state_size = 1 << n_qubits;
1457 let mut state = Array1::zeros(state_size);
1458
1459 state[0] = Complex64::new(1.0, 0.0);
1461
1462 for (i, &angle) in input.iter().enumerate() {
1464 if i < n_qubits {
1465 state = self.apply_ry_rotation(&state, i, angle)?;
1467 }
1468 }
1469
1470 Ok(state)
1471 }
1472
1473 fn encode_basis(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1475 let n_qubits = self.config.num_qubits;
1476 let state_size = 1 << n_qubits;
1477 let mut state = Array1::zeros(state_size);
1478
1479 let mut binary_index = 0;
1481 for (i, &val) in input.iter().enumerate() {
1482 if i < n_qubits && val > 0.5 {
1483 binary_index |= 1 << i;
1484 }
1485 }
1486
1487 state[binary_index] = Complex64::new(1.0, 0.0);
1488
1489 Ok(state)
1490 }
1491
1492 fn encode_quantum_feature_map(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1494 let n_qubits = self.config.num_qubits;
1495 let state_size = 1 << n_qubits;
1496 let mut state = Array1::zeros(state_size);
1497
1498 let hadamard_coeff = 1.0 / (2.0_f64.powf(n_qubits as f64 / 2.0));
1500 for i in 0..state_size {
1501 state[i] = Complex64::new(hadamard_coeff, 0.0);
1502 }
1503
1504 for (i, &feature) in input.iter().enumerate() {
1506 if i < n_qubits {
1507 state = self.apply_rz_rotation(&state, i, feature * PI)?;
1509 }
1510 }
1511
1512 for i in 0..(n_qubits - 1) {
1514 if i + 1 < input.len() {
1515 let interaction = input[i] * input[i + 1];
1516 state = self.apply_cnot_interaction(&state, i, i + 1, interaction * PI)?;
1517 }
1518 }
1519
1520 Ok(state)
1521 }
1522
1523 fn apply_ry_rotation(
1525 &self,
1526 state: &Array1<Complex64>,
1527 qubit: usize,
1528 angle: f64,
1529 ) -> Result<Array1<Complex64>> {
1530 let n_qubits = self.config.num_qubits;
1531 let state_size = 1 << n_qubits;
1532 let mut new_state = state.clone();
1533
1534 let cos_half = (angle / 2.0).cos();
1535 let sin_half = (angle / 2.0).sin();
1536
1537 for i in 0..state_size {
1538 if i & (1 << qubit) == 0 {
1539 let j = i | (1 << qubit); if j < state_size {
1542 let state_0 = state[i];
1543 let state_1 = state[j];
1544
1545 new_state[i] = Complex64::new(cos_half, 0.0) * state_0
1546 - Complex64::new(sin_half, 0.0) * state_1;
1547 new_state[j] = Complex64::new(sin_half, 0.0) * state_0
1548 + Complex64::new(cos_half, 0.0) * state_1;
1549 }
1550 }
1551 }
1552
1553 Ok(new_state)
1554 }
1555
1556 fn apply_rz_rotation(
1558 &self,
1559 state: &Array1<Complex64>,
1560 qubit: usize,
1561 angle: f64,
1562 ) -> Result<Array1<Complex64>> {
1563 let n_qubits = self.config.num_qubits;
1564 let state_size = 1 << n_qubits;
1565 let mut new_state = state.clone();
1566
1567 let phase_0 = Complex64::from_polar(1.0, -angle / 2.0);
1568 let phase_1 = Complex64::from_polar(1.0, angle / 2.0);
1569
1570 for i in 0..state_size {
1571 if i & (1 << qubit) == 0 {
1572 new_state[i] *= phase_0;
1573 } else {
1574 new_state[i] *= phase_1;
1575 }
1576 }
1577
1578 Ok(new_state)
1579 }
1580
1581 fn apply_cnot_interaction(
1583 &self,
1584 state: &Array1<Complex64>,
1585 control: usize,
1586 target: usize,
1587 interaction: f64,
1588 ) -> Result<Array1<Complex64>> {
1589 let n_qubits = self.config.num_qubits;
1590 let state_size = 1 << n_qubits;
1591 let mut new_state = state.clone();
1592
1593 let phase = Complex64::from_polar(1.0, interaction);
1595
1596 for i in 0..state_size {
1597 if (i & (1 << control)) != 0 && (i & (1 << target)) != 0 {
1598 new_state[i] *= phase;
1600 }
1601 }
1602
1603 Ok(new_state)
1604 }
1605
1606 fn decode_output(&self, state: &Array1<Complex64>) -> Result<Array1<f64>> {
1608 let n_qubits = self.config.num_qubits;
1610 let mut output = Array1::zeros(n_qubits);
1611
1612 for qubit in 0..n_qubits {
1613 let expectation = self.measure_pauli_z_expectation(state, qubit)?;
1614 output[qubit] = expectation;
1615 }
1616
1617 Ok(output)
1618 }
1619
1620 fn measure_pauli_z_expectation(&self, state: &Array1<Complex64>, qubit: usize) -> Result<f64> {
1622 let state_size = state.len();
1623 let mut expectation = 0.0;
1624
1625 for i in 0..state_size {
1626 let probability = state[i].norm_sqr();
1627 if i & (1 << qubit) == 0 {
1628 expectation += probability; } else {
1630 expectation -= probability; }
1632 }
1633
1634 Ok(expectation)
1635 }
1636
1637 fn compute_loss(&self, prediction: &Array1<f64>, target: &Array1<f64>) -> Result<f64> {
1639 if prediction.shape() != target.shape() {
1641 return Err(SimulatorError::InvalidInput(format!(
1642 "Shape mismatch: prediction shape {:?} != target shape {:?}",
1643 prediction.shape(),
1644 target.shape()
1645 )));
1646 }
1647
1648 let diff = prediction - target;
1650 let mse = diff.iter().map(|x| x * x).sum::<f64>() / diff.len() as f64;
1651 Ok(mse)
1652 }
1653
1654 fn compute_loss_gradient(
1656 &self,
1657 prediction: &Array1<f64>,
1658 target: &Array1<f64>,
1659 ) -> Result<Array1<f64>> {
1660 let diff = prediction - target;
1662 let grad = 2.0 * &diff / diff.len() as f64;
1663 Ok(grad)
1664 }
1665
1666 fn compute_gradients(&mut self, loss_gradient: &Array1<f64>) -> Result<Vec<Array1<f64>>> {
1668 let mut gradients = Vec::new();
1669
1670 for layer_idx in 0..self.layers.len() {
1671 let layer_gradient = match self.config.training_config.gradient_method {
1672 GradientMethod::ParameterShift => {
1673 self.compute_parameter_shift_gradient(layer_idx, loss_gradient)?
1674 }
1675 GradientMethod::FiniteDifference => {
1676 self.compute_finite_difference_gradient(layer_idx, loss_gradient)?
1677 }
1678 _ => {
1679 return Err(SimulatorError::InvalidConfiguration(
1680 "Gradient method not implemented".to_string(),
1681 ))
1682 }
1683 };
1684 gradients.push(layer_gradient);
1685 }
1686
1687 Ok(gradients)
1688 }
1689
1690 fn compute_parameter_shift_gradient(
1692 &mut self,
1693 layer_idx: usize,
1694 loss_gradient: &Array1<f64>,
1695 ) -> Result<Array1<f64>> {
1696 let layer = &self.layers[layer_idx];
1697 let parameters = layer.get_parameters();
1698 let mut gradient = Array1::zeros(parameters.len());
1699
1700 let shift = PI / 2.0; for (param_idx, ¶m_val) in parameters.iter().enumerate() {
1703 let mut params_plus = parameters.clone();
1705 params_plus[param_idx] = param_val + shift;
1706 self.layers[layer_idx].set_parameters(¶ms_plus);
1707 let output_plus = self.forward_layer(layer_idx, loss_gradient)?;
1708
1709 let mut params_minus = parameters.clone();
1711 params_minus[param_idx] = param_val - shift;
1712 self.layers[layer_idx].set_parameters(¶ms_minus);
1713 let output_minus = self.forward_layer(layer_idx, loss_gradient)?;
1714
1715 gradient[param_idx] = (output_plus.sum() - output_minus.sum()) / 2.0;
1717
1718 self.layers[layer_idx].set_parameters(¶meters);
1720 }
1721
1722 Ok(gradient)
1723 }
1724
1725 fn compute_finite_difference_gradient(
1727 &mut self,
1728 layer_idx: usize,
1729 loss_gradient: &Array1<f64>,
1730 ) -> Result<Array1<f64>> {
1731 let layer = &self.layers[layer_idx];
1732 let parameters = layer.get_parameters();
1733 let mut gradient = Array1::zeros(parameters.len());
1734
1735 let eps = 1e-6; for (param_idx, ¶m_val) in parameters.iter().enumerate() {
1738 let mut params_plus = parameters.clone();
1740 params_plus[param_idx] = param_val + eps;
1741 self.layers[layer_idx].set_parameters(¶ms_plus);
1742 let output_plus = self.forward_layer(layer_idx, loss_gradient)?;
1743
1744 let mut params_minus = parameters.clone();
1746 params_minus[param_idx] = param_val - eps;
1747 self.layers[layer_idx].set_parameters(¶ms_minus);
1748 let output_minus = self.forward_layer(layer_idx, loss_gradient)?;
1749
1750 gradient[param_idx] = (output_plus.sum() - output_minus.sum()) / (2.0 * eps);
1752
1753 self.layers[layer_idx].set_parameters(¶meters);
1755 }
1756
1757 Ok(gradient)
1758 }
1759
1760 fn forward_layer(&mut self, layer_idx: usize, input: &Array1<f64>) -> Result<Array1<f64>> {
1762 self.forward(input)
1764 }
1765
1766 fn apply_gradients(&mut self, gradients: &[Array1<f64>]) -> Result<()> {
1768 for (layer_idx, gradient) in gradients.iter().enumerate() {
1769 let layer = &mut self.layers[layer_idx];
1770 let mut parameters = layer.get_parameters();
1771
1772 match self.config.training_config.optimizer {
1774 OptimizerType::SGD => {
1775 for (param, grad) in parameters.iter_mut().zip(gradient.iter()) {
1776 *param -= self.config.training_config.learning_rate * grad;
1777 }
1778 }
1779 OptimizerType::Adam => {
1780 for (param, grad) in parameters.iter_mut().zip(gradient.iter()) {
1782 *param -= self.config.training_config.learning_rate * grad;
1783 }
1784 }
1785 _ => {
1786 for (param, grad) in parameters.iter_mut().zip(gradient.iter()) {
1788 *param -= self.config.training_config.learning_rate * grad;
1789 }
1790 }
1791 }
1792
1793 if let Some((min_val, max_val)) =
1795 self.config.training_config.regularization.parameter_bounds
1796 {
1797 for param in parameters.iter_mut() {
1798 *param = param.clamp(min_val, max_val);
1799 }
1800 }
1801
1802 layer.set_parameters(¶meters);
1803 }
1804
1805 Ok(())
1806 }
1807
1808 fn get_current_learning_rate(&self, epoch: usize) -> f64 {
1810 let base_lr = self.config.training_config.learning_rate;
1811
1812 match self.config.training_config.lr_schedule {
1813 LearningRateSchedule::Constant => base_lr,
1814 LearningRateSchedule::ExponentialDecay => base_lr * 0.95_f64.powi(epoch as i32),
1815 LearningRateSchedule::StepDecay => {
1816 if epoch % 50 == 0 && epoch > 0 {
1817 base_lr * 0.5_f64.powi((epoch / 50) as i32)
1818 } else {
1819 base_lr
1820 }
1821 }
1822 LearningRateSchedule::CosineAnnealing => {
1823 let progress = epoch as f64 / self.config.training_config.epochs as f64;
1824 base_lr * 0.5 * (1.0 + (PI * progress).cos())
1825 }
1826 _ => base_lr,
1827 }
1828 }
1829
1830 fn update_learning_rate(&mut self, epoch: usize, validation_loss: f64) {
1832 let current_lr = self.get_current_learning_rate(epoch);
1835 self.training_state.current_learning_rate = current_lr;
1836 }
1837
1838 fn compute_quantum_advantage_metrics(&self) -> Result<QuantumAdvantageMetrics> {
1840 Ok(QuantumAdvantageMetrics {
1842 quantum_volume: 0.0,
1843 classical_simulation_cost: 0.0,
1844 quantum_speedup_factor: 1.0,
1845 circuit_depth: self.layers.iter().map(|l| l.get_depth()).sum(),
1846 gate_count: self.layers.iter().map(|l| l.get_gate_count()).sum(),
1847 entanglement_measure: 0.0,
1848 })
1849 }
1850
1851 pub fn get_stats(&self) -> &QMLStats {
1853 &self.stats
1854 }
1855
1856 pub fn get_training_history(&self) -> &[QMLTrainingResult] {
1858 &self.training_history
1859 }
1860
1861 pub fn get_layers(&self) -> &[Box<dyn QMLLayer>] {
1863 &self.layers
1864 }
1865
1866 pub fn get_config(&self) -> &QMLConfig {
1868 &self.config
1869 }
1870
1871 pub fn encode_amplitude_public(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1873 self.encode_amplitude(input)
1874 }
1875
1876 pub fn encode_angle_public(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1878 self.encode_angle(input)
1879 }
1880
1881 pub fn encode_basis_public(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1883 self.encode_basis(input)
1884 }
1885
1886 pub fn encode_quantum_feature_map_public(
1888 &self,
1889 input: &Array1<f64>,
1890 ) -> Result<Array1<Complex64>> {
1891 self.encode_quantum_feature_map(input)
1892 }
1893
1894 pub fn measure_pauli_z_expectation_public(
1896 &self,
1897 state: &Array1<Complex64>,
1898 qubit: usize,
1899 ) -> Result<f64> {
1900 self.measure_pauli_z_expectation(state, qubit)
1901 }
1902
1903 pub fn get_current_learning_rate_public(&self, epoch: usize) -> f64 {
1905 self.get_current_learning_rate(epoch)
1906 }
1907
1908 pub fn compute_loss_public(
1910 &self,
1911 prediction: &Array1<f64>,
1912 target: &Array1<f64>,
1913 ) -> Result<f64> {
1914 self.compute_loss(prediction, target)
1915 }
1916
1917 pub fn compute_loss_gradient_public(
1919 &self,
1920 prediction: &Array1<f64>,
1921 target: &Array1<f64>,
1922 ) -> Result<Array1<f64>> {
1923 self.compute_loss_gradient(prediction, target)
1924 }
1925}
1926
1927pub trait QMLLayer: std::fmt::Debug + Send + Sync {
1929 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>>;
1931
1932 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>>;
1934
1935 fn get_parameters(&self) -> Array1<f64>;
1937
1938 fn set_parameters(&mut self, parameters: &Array1<f64>);
1940
1941 fn get_depth(&self) -> usize;
1943
1944 fn get_gate_count(&self) -> usize;
1946
1947 fn get_num_parameters(&self) -> usize;
1949}
1950
1951#[derive(Debug)]
1953pub struct ParameterizedQuantumCircuitLayer {
1954 num_qubits: usize,
1956 config: QMLLayerConfig,
1958 parameters: Array1<f64>,
1960 circuit_structure: Vec<PQCGate>,
1962 simulator: StateVectorSimulator,
1964}
1965
1966impl ParameterizedQuantumCircuitLayer {
1967 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
1969 let mut layer = Self {
1970 num_qubits,
1971 config: config.clone(),
1972 parameters: Array1::zeros(config.num_parameters),
1973 circuit_structure: Vec::new(),
1974 simulator: StateVectorSimulator::new(),
1975 };
1976
1977 layer.initialize_parameters();
1979
1980 layer.build_circuit_structure()?;
1982
1983 Ok(layer)
1984 }
1985
1986 fn initialize_parameters(&mut self) {
1988 let mut rng = thread_rng();
1989 for param in self.parameters.iter_mut() {
1990 *param = rng.gen_range(-PI..PI);
1991 }
1992 }
1993
1994 fn build_circuit_structure(&mut self) -> Result<()> {
1996 match self.config.ansatz_type {
1997 AnsatzType::Hardware => self.build_hardware_efficient_ansatz(),
1998 AnsatzType::Layered => self.build_layered_ansatz(),
1999 AnsatzType::BrickWall => self.build_brick_wall_ansatz(),
2000 _ => Err(SimulatorError::InvalidConfiguration(
2001 "Ansatz type not implemented".to_string(),
2002 )),
2003 }
2004 }
2005
2006 fn build_hardware_efficient_ansatz(&mut self) -> Result<()> {
2008 let mut param_idx = 0;
2009
2010 for layer in 0..self.config.depth {
2011 for qubit in 0..self.num_qubits {
2013 for &gate_type in &self.config.rotation_gates {
2014 if param_idx < self.parameters.len() {
2015 self.circuit_structure.push(PQCGate {
2016 gate_type: PQCGateType::SingleQubit(gate_type),
2017 qubits: vec![qubit],
2018 parameter_index: Some(param_idx),
2019 });
2020 param_idx += 1;
2021 }
2022 }
2023 }
2024
2025 self.add_entangling_gates(&mut param_idx);
2027 }
2028
2029 Ok(())
2030 }
2031
2032 fn build_layered_ansatz(&mut self) -> Result<()> {
2034 self.build_hardware_efficient_ansatz()
2036 }
2037
2038 fn build_brick_wall_ansatz(&mut self) -> Result<()> {
2040 let mut param_idx = 0;
2041
2042 for layer in 0..self.config.depth {
2043 let offset = layer % 2;
2045 for i in (offset..self.num_qubits - 1).step_by(2) {
2046 self.circuit_structure.push(PQCGate {
2047 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2048 qubits: vec![i, i + 1],
2049 parameter_index: None,
2050 });
2051 }
2052
2053 for qubit in 0..self.num_qubits {
2055 if param_idx < self.parameters.len() {
2056 self.circuit_structure.push(PQCGate {
2057 gate_type: PQCGateType::SingleQubit(RotationGate::RY),
2058 qubits: vec![qubit],
2059 parameter_index: Some(param_idx),
2060 });
2061 param_idx += 1;
2062 }
2063 }
2064 }
2065
2066 Ok(())
2067 }
2068
2069 fn add_entangling_gates(&mut self, param_idx: &mut usize) {
2071 match self.config.entanglement_pattern {
2072 EntanglementPattern::Linear => {
2073 for i in 0..(self.num_qubits - 1) {
2074 self.circuit_structure.push(PQCGate {
2075 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2076 qubits: vec![i, i + 1],
2077 parameter_index: None,
2078 });
2079 }
2080 }
2081 EntanglementPattern::Circular => {
2082 for i in 0..self.num_qubits {
2083 let next = (i + 1) % self.num_qubits;
2084 self.circuit_structure.push(PQCGate {
2085 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2086 qubits: vec![i, next],
2087 parameter_index: None,
2088 });
2089 }
2090 }
2091 EntanglementPattern::AllToAll => {
2092 for i in 0..self.num_qubits {
2093 for j in (i + 1)..self.num_qubits {
2094 self.circuit_structure.push(PQCGate {
2095 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2096 qubits: vec![i, j],
2097 parameter_index: None,
2098 });
2099 }
2100 }
2101 }
2102 _ => {
2103 for i in 0..(self.num_qubits - 1) {
2105 self.circuit_structure.push(PQCGate {
2106 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2107 qubits: vec![i, i + 1],
2108 parameter_index: None,
2109 });
2110 }
2111 }
2112 }
2113 }
2114}
2115
2116impl QMLLayer for ParameterizedQuantumCircuitLayer {
2117 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2118 let mut state = input.clone();
2119
2120 for gate in &self.circuit_structure {
2122 state = self.apply_gate(&state, gate)?;
2123 }
2124
2125 Ok(state)
2126 }
2127
2128 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2129 Ok(gradient.clone())
2131 }
2132
2133 fn get_parameters(&self) -> Array1<f64> {
2134 self.parameters.clone()
2135 }
2136
2137 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2138 self.parameters = parameters.clone();
2139 }
2140
2141 fn get_depth(&self) -> usize {
2142 self.config.depth
2143 }
2144
2145 fn get_gate_count(&self) -> usize {
2146 self.circuit_structure.len()
2147 }
2148
2149 fn get_num_parameters(&self) -> usize {
2150 self.parameters.len()
2151 }
2152}
2153
2154impl ParameterizedQuantumCircuitLayer {
2155 fn apply_gate(&self, state: &Array1<Complex64>, gate: &PQCGate) -> Result<Array1<Complex64>> {
2157 match &gate.gate_type {
2158 PQCGateType::SingleQubit(rotation_gate) => {
2159 let angle = if let Some(param_idx) = gate.parameter_index {
2160 self.parameters[param_idx]
2161 } else {
2162 0.0
2163 };
2164 self.apply_single_qubit_gate(state, gate.qubits[0], *rotation_gate, angle)
2165 }
2166 PQCGateType::TwoQubit(two_qubit_gate) => {
2167 self.apply_two_qubit_gate(state, gate.qubits[0], gate.qubits[1], *two_qubit_gate)
2168 }
2169 }
2170 }
2171
2172 fn apply_single_qubit_gate(
2174 &self,
2175 state: &Array1<Complex64>,
2176 qubit: usize,
2177 gate_type: RotationGate,
2178 angle: f64,
2179 ) -> Result<Array1<Complex64>> {
2180 let state_size = state.len();
2181 let mut new_state = Array1::zeros(state_size);
2182
2183 match gate_type {
2184 RotationGate::RX => {
2185 let cos_half = (angle / 2.0).cos();
2186 let sin_half = (angle / 2.0).sin();
2187
2188 for i in 0..state_size {
2189 if i & (1 << qubit) == 0 {
2190 let j = i | (1 << qubit);
2191 if j < state_size {
2192 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2193 + Complex64::new(0.0, -sin_half) * state[j];
2194 new_state[j] = Complex64::new(0.0, -sin_half) * state[i]
2195 + Complex64::new(cos_half, 0.0) * state[j];
2196 }
2197 }
2198 }
2199 }
2200 RotationGate::RY => {
2201 let cos_half = (angle / 2.0).cos();
2202 let sin_half = (angle / 2.0).sin();
2203
2204 for i in 0..state_size {
2205 if i & (1 << qubit) == 0 {
2206 let j = i | (1 << qubit);
2207 if j < state_size {
2208 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2209 - Complex64::new(sin_half, 0.0) * state[j];
2210 new_state[j] = Complex64::new(sin_half, 0.0) * state[i]
2211 + Complex64::new(cos_half, 0.0) * state[j];
2212 }
2213 }
2214 }
2215 }
2216 RotationGate::RZ => {
2217 let phase_0 = Complex64::from_polar(1.0, -angle / 2.0);
2218 let phase_1 = Complex64::from_polar(1.0, angle / 2.0);
2219
2220 for i in 0..state_size {
2221 if i & (1 << qubit) == 0 {
2222 new_state[i] = phase_0 * state[i];
2223 } else {
2224 new_state[i] = phase_1 * state[i];
2225 }
2226 }
2227 }
2228 _ => {
2229 return Err(SimulatorError::InvalidGate(
2230 "Gate type not implemented".to_string(),
2231 ))
2232 }
2233 }
2234
2235 Ok(new_state)
2236 }
2237
2238 fn apply_two_qubit_gate(
2240 &self,
2241 state: &Array1<Complex64>,
2242 control: usize,
2243 target: usize,
2244 gate_type: TwoQubitGate,
2245 ) -> Result<Array1<Complex64>> {
2246 let state_size = state.len();
2247 let mut new_state = state.clone();
2248
2249 match gate_type {
2250 TwoQubitGate::CNOT => {
2251 for i in 0..state_size {
2252 if (i & (1 << control)) != 0 {
2253 let j = i ^ (1 << target);
2255 new_state[i] = state[j];
2256 }
2257 }
2258 }
2259 TwoQubitGate::CZ => {
2260 for i in 0..state_size {
2261 if (i & (1 << control)) != 0 && (i & (1 << target)) != 0 {
2262 new_state[i] = -state[i];
2264 }
2265 }
2266 }
2267 TwoQubitGate::SWAP => {
2268 for i in 0..state_size {
2269 let ctrl_bit = (i & (1 << control)) != 0;
2270 let targ_bit = (i & (1 << target)) != 0;
2271 if ctrl_bit != targ_bit {
2272 let j = i ^ (1 << control) ^ (1 << target);
2274 new_state[i] = state[j];
2275 }
2276 }
2277 }
2278 TwoQubitGate::CPhase => {
2279 for i in 0..state_size {
2280 if (i & (1 << control)) != 0 && (i & (1 << target)) != 0 {
2281 new_state[i] = -state[i];
2283 }
2284 }
2285 }
2286 }
2287
2288 Ok(new_state)
2289 }
2290}
2291
2292#[derive(Debug)]
2294pub struct QuantumConvolutionalLayer {
2295 num_qubits: usize,
2297 config: QMLLayerConfig,
2299 parameters: Array1<f64>,
2301 conv_structure: Vec<ConvolutionalFilter>,
2303}
2304
2305impl QuantumConvolutionalLayer {
2306 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2308 let mut layer = Self {
2309 num_qubits,
2310 config: config.clone(),
2311 parameters: Array1::zeros(config.num_parameters),
2312 conv_structure: Vec::new(),
2313 };
2314
2315 layer.initialize_parameters();
2316 layer.build_convolutional_structure()?;
2317
2318 Ok(layer)
2319 }
2320
2321 fn initialize_parameters(&mut self) {
2323 let mut rng = thread_rng();
2324 for param in self.parameters.iter_mut() {
2325 *param = rng.gen_range(-PI..PI);
2326 }
2327 }
2328
2329 fn build_convolutional_structure(&mut self) -> Result<()> {
2331 let filter_size = 2; let stride = 1;
2334
2335 let mut param_idx = 0;
2336 for start in (0..self.num_qubits - filter_size + 1).step_by(stride) {
2337 if param_idx + 2 <= self.parameters.len() {
2338 self.conv_structure.push(ConvolutionalFilter {
2339 qubits: vec![start, start + 1],
2340 parameter_indices: vec![param_idx, param_idx + 1],
2341 });
2342 param_idx += 2;
2343 }
2344 }
2345
2346 Ok(())
2347 }
2348}
2349
2350impl QMLLayer for QuantumConvolutionalLayer {
2351 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2352 let mut state = input.clone();
2353
2354 for filter in &self.conv_structure {
2356 state = self.apply_convolutional_filter(&state, filter)?;
2357 }
2358
2359 Ok(state)
2360 }
2361
2362 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2363 Ok(gradient.clone())
2364 }
2365
2366 fn get_parameters(&self) -> Array1<f64> {
2367 self.parameters.clone()
2368 }
2369
2370 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2371 self.parameters = parameters.clone();
2372 }
2373
2374 fn get_depth(&self) -> usize {
2375 self.conv_structure.len()
2376 }
2377
2378 fn get_gate_count(&self) -> usize {
2379 self.conv_structure.len() * 4 }
2381
2382 fn get_num_parameters(&self) -> usize {
2383 self.parameters.len()
2384 }
2385}
2386
2387impl QuantumConvolutionalLayer {
2388 fn apply_convolutional_filter(
2390 &self,
2391 state: &Array1<Complex64>,
2392 filter: &ConvolutionalFilter,
2393 ) -> Result<Array1<Complex64>> {
2394 let mut new_state = state.clone();
2395
2396 let param1 = self.parameters[filter.parameter_indices[0]];
2398 let param2 = self.parameters[filter.parameter_indices[1]];
2399
2400 new_state = self.apply_ry_to_state(&new_state, filter.qubits[0], param1)?;
2402 new_state = self.apply_ry_to_state(&new_state, filter.qubits[1], param2)?;
2403 new_state = self.apply_cnot_to_state(&new_state, filter.qubits[0], filter.qubits[1])?;
2404
2405 Ok(new_state)
2406 }
2407
2408 fn apply_ry_to_state(
2410 &self,
2411 state: &Array1<Complex64>,
2412 qubit: usize,
2413 angle: f64,
2414 ) -> Result<Array1<Complex64>> {
2415 let state_size = state.len();
2416 let mut new_state = Array1::zeros(state_size);
2417
2418 let cos_half = (angle / 2.0).cos();
2419 let sin_half = (angle / 2.0).sin();
2420
2421 for i in 0..state_size {
2422 if i & (1 << qubit) == 0 {
2423 let j = i | (1 << qubit);
2424 if j < state_size {
2425 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2426 - Complex64::new(sin_half, 0.0) * state[j];
2427 new_state[j] = Complex64::new(sin_half, 0.0) * state[i]
2428 + Complex64::new(cos_half, 0.0) * state[j];
2429 }
2430 }
2431 }
2432
2433 Ok(new_state)
2434 }
2435
2436 fn apply_cnot_to_state(
2438 &self,
2439 state: &Array1<Complex64>,
2440 control: usize,
2441 target: usize,
2442 ) -> Result<Array1<Complex64>> {
2443 let state_size = state.len();
2444 let mut new_state = state.clone();
2445
2446 for i in 0..state_size {
2447 if (i & (1 << control)) != 0 {
2448 let j = i ^ (1 << target);
2449 new_state[i] = state[j];
2450 }
2451 }
2452
2453 Ok(new_state)
2454 }
2455}
2456
2457#[derive(Debug)]
2459pub struct QuantumDenseLayer {
2460 num_qubits: usize,
2462 config: QMLLayerConfig,
2464 parameters: Array1<f64>,
2466 dense_structure: Vec<DenseConnection>,
2468}
2469
2470impl QuantumDenseLayer {
2471 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2473 let mut layer = Self {
2474 num_qubits,
2475 config: config.clone(),
2476 parameters: Array1::zeros(config.num_parameters),
2477 dense_structure: Vec::new(),
2478 };
2479
2480 layer.initialize_parameters();
2481 layer.build_dense_structure()?;
2482
2483 Ok(layer)
2484 }
2485
2486 fn initialize_parameters(&mut self) {
2488 let mut rng = thread_rng();
2489 for param in self.parameters.iter_mut() {
2490 *param = rng.gen_range(-PI..PI);
2491 }
2492 }
2493
2494 fn build_dense_structure(&mut self) -> Result<()> {
2496 let mut param_idx = 0;
2497
2498 for i in 0..self.num_qubits {
2500 for j in (i + 1)..self.num_qubits {
2501 if param_idx < self.parameters.len() {
2502 self.dense_structure.push(DenseConnection {
2503 qubit1: i,
2504 qubit2: j,
2505 parameter_index: param_idx,
2506 });
2507 param_idx += 1;
2508 }
2509 }
2510 }
2511
2512 Ok(())
2513 }
2514}
2515
2516impl QMLLayer for QuantumDenseLayer {
2517 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2518 let mut state = input.clone();
2519
2520 for connection in &self.dense_structure {
2522 state = self.apply_dense_connection(&state, connection)?;
2523 }
2524
2525 Ok(state)
2526 }
2527
2528 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2529 Ok(gradient.clone())
2530 }
2531
2532 fn get_parameters(&self) -> Array1<f64> {
2533 self.parameters.clone()
2534 }
2535
2536 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2537 self.parameters = parameters.clone();
2538 }
2539
2540 fn get_depth(&self) -> usize {
2541 1 }
2543
2544 fn get_gate_count(&self) -> usize {
2545 self.dense_structure.len() * 2 }
2547
2548 fn get_num_parameters(&self) -> usize {
2549 self.parameters.len()
2550 }
2551}
2552
2553impl QuantumDenseLayer {
2554 fn apply_dense_connection(
2556 &self,
2557 state: &Array1<Complex64>,
2558 connection: &DenseConnection,
2559 ) -> Result<Array1<Complex64>> {
2560 let angle = self.parameters[connection.parameter_index];
2561
2562 self.apply_parameterized_two_qubit_gate(state, connection.qubit1, connection.qubit2, angle)
2564 }
2565
2566 fn apply_parameterized_two_qubit_gate(
2568 &self,
2569 state: &Array1<Complex64>,
2570 qubit1: usize,
2571 qubit2: usize,
2572 angle: f64,
2573 ) -> Result<Array1<Complex64>> {
2574 let state_size = state.len();
2575 let mut new_state = state.clone();
2576
2577 let cos_val = angle.cos();
2579 let sin_val = angle.sin();
2580
2581 for i in 0..state_size {
2582 if (i & (1 << qubit1)) != 0 && (i & (1 << qubit2)) != 0 {
2583 let phase = Complex64::new(cos_val, sin_val);
2585 new_state[i] *= phase;
2586 }
2587 }
2588
2589 Ok(new_state)
2590 }
2591}
2592
2593#[derive(Debug)]
2595pub struct QuantumLSTMLayer {
2596 num_qubits: usize,
2598 config: QMLLayerConfig,
2600 parameters: Array1<f64>,
2602 lstm_gates: Vec<LSTMGate>,
2604 hidden_state: Option<Array1<Complex64>>,
2606 cell_state: Option<Array1<Complex64>>,
2608}
2609
2610impl QuantumLSTMLayer {
2611 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2613 let mut layer = Self {
2614 num_qubits,
2615 config: config.clone(),
2616 parameters: Array1::zeros(config.num_parameters),
2617 lstm_gates: Vec::new(),
2618 hidden_state: None,
2619 cell_state: None,
2620 };
2621
2622 layer.initialize_parameters();
2623 layer.build_lstm_structure()?;
2624
2625 Ok(layer)
2626 }
2627
2628 fn initialize_parameters(&mut self) {
2630 let mut rng = thread_rng();
2631 for param in self.parameters.iter_mut() {
2632 *param = rng.gen_range(-PI..PI);
2633 }
2634 }
2635
2636 fn build_lstm_structure(&mut self) -> Result<()> {
2638 let params_per_gate = self.parameters.len() / 4; self.lstm_gates = vec![
2641 LSTMGate {
2642 gate_type: LSTMGateType::Forget,
2643 parameter_start: 0,
2644 parameter_count: params_per_gate,
2645 },
2646 LSTMGate {
2647 gate_type: LSTMGateType::Input,
2648 parameter_start: params_per_gate,
2649 parameter_count: params_per_gate,
2650 },
2651 LSTMGate {
2652 gate_type: LSTMGateType::Output,
2653 parameter_start: 2 * params_per_gate,
2654 parameter_count: params_per_gate,
2655 },
2656 LSTMGate {
2657 gate_type: LSTMGateType::Candidate,
2658 parameter_start: 3 * params_per_gate,
2659 parameter_count: params_per_gate,
2660 },
2661 ];
2662
2663 Ok(())
2664 }
2665}
2666
2667impl QMLLayer for QuantumLSTMLayer {
2668 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2669 if self.hidden_state.is_none() {
2671 let state_size = 1 << self.num_qubits;
2672 self.hidden_state = Some(Array1::zeros(state_size));
2673 self.cell_state = Some(Array1::zeros(state_size));
2674 self.hidden_state.as_mut().unwrap()[0] = Complex64::new(1.0, 0.0);
2676 self.cell_state.as_mut().unwrap()[0] = Complex64::new(1.0, 0.0);
2677 }
2678
2679 let mut current_state = input.clone();
2680
2681 for gate in &self.lstm_gates {
2683 current_state = self.apply_lstm_gate(¤t_state, gate)?;
2684 }
2685
2686 self.hidden_state = Some(current_state.clone());
2688
2689 Ok(current_state)
2690 }
2691
2692 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2693 Ok(gradient.clone())
2694 }
2695
2696 fn get_parameters(&self) -> Array1<f64> {
2697 self.parameters.clone()
2698 }
2699
2700 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2701 self.parameters = parameters.clone();
2702 }
2703
2704 fn get_depth(&self) -> usize {
2705 self.lstm_gates.len()
2706 }
2707
2708 fn get_gate_count(&self) -> usize {
2709 self.parameters.len() }
2711
2712 fn get_num_parameters(&self) -> usize {
2713 self.parameters.len()
2714 }
2715}
2716
2717impl QuantumLSTMLayer {
2718 fn apply_lstm_gate(
2720 &self,
2721 state: &Array1<Complex64>,
2722 gate: &LSTMGate,
2723 ) -> Result<Array1<Complex64>> {
2724 let mut new_state = state.clone();
2725
2726 for i in 0..gate.parameter_count {
2728 let param_idx = gate.parameter_start + i;
2729 if param_idx < self.parameters.len() {
2730 let angle = self.parameters[param_idx];
2731 let qubit = i % self.num_qubits;
2732
2733 new_state = self.apply_rotation(&new_state, qubit, angle)?;
2735 }
2736 }
2737
2738 Ok(new_state)
2739 }
2740
2741 fn apply_rotation(
2743 &self,
2744 state: &Array1<Complex64>,
2745 qubit: usize,
2746 angle: f64,
2747 ) -> Result<Array1<Complex64>> {
2748 let state_size = state.len();
2749 let mut new_state = Array1::zeros(state_size);
2750
2751 let cos_half = (angle / 2.0).cos();
2752 let sin_half = (angle / 2.0).sin();
2753
2754 for i in 0..state_size {
2755 if i & (1 << qubit) == 0 {
2756 let j = i | (1 << qubit);
2757 if j < state_size {
2758 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2759 - Complex64::new(sin_half, 0.0) * state[j];
2760 new_state[j] = Complex64::new(sin_half, 0.0) * state[i]
2761 + Complex64::new(cos_half, 0.0) * state[j];
2762 }
2763 }
2764 }
2765
2766 Ok(new_state)
2767 }
2768
2769 pub fn get_lstm_gates(&self) -> &[LSTMGate] {
2771 &self.lstm_gates
2772 }
2773}
2774
2775#[derive(Debug)]
2777pub struct QuantumAttentionLayer {
2778 num_qubits: usize,
2780 config: QMLLayerConfig,
2782 parameters: Array1<f64>,
2784 attention_structure: Vec<AttentionHead>,
2786}
2787
2788impl QuantumAttentionLayer {
2789 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2791 let mut layer = Self {
2792 num_qubits,
2793 config: config.clone(),
2794 parameters: Array1::zeros(config.num_parameters),
2795 attention_structure: Vec::new(),
2796 };
2797
2798 layer.initialize_parameters();
2799 layer.build_attention_structure()?;
2800
2801 Ok(layer)
2802 }
2803
2804 fn initialize_parameters(&mut self) {
2806 let mut rng = thread_rng();
2807 for param in self.parameters.iter_mut() {
2808 *param = rng.gen_range(-PI..PI);
2809 }
2810 }
2811
2812 fn build_attention_structure(&mut self) -> Result<()> {
2814 let num_heads = 2; let params_per_head = self.parameters.len() / num_heads;
2816
2817 for head in 0..num_heads {
2818 self.attention_structure.push(AttentionHead {
2819 head_id: head,
2820 parameter_start: head * params_per_head,
2821 parameter_count: params_per_head,
2822 query_qubits: (0..self.num_qubits / 2).collect(),
2823 key_qubits: (self.num_qubits / 2..self.num_qubits).collect(),
2824 });
2825 }
2826
2827 Ok(())
2828 }
2829}
2830
2831impl QMLLayer for QuantumAttentionLayer {
2832 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2833 let mut state = input.clone();
2834
2835 for head in &self.attention_structure {
2837 state = self.apply_attention_head(&state, head)?;
2838 }
2839
2840 Ok(state)
2841 }
2842
2843 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2844 Ok(gradient.clone())
2845 }
2846
2847 fn get_parameters(&self) -> Array1<f64> {
2848 self.parameters.clone()
2849 }
2850
2851 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2852 self.parameters = parameters.clone();
2853 }
2854
2855 fn get_depth(&self) -> usize {
2856 self.attention_structure.len()
2857 }
2858
2859 fn get_gate_count(&self) -> usize {
2860 self.parameters.len()
2861 }
2862
2863 fn get_num_parameters(&self) -> usize {
2864 self.parameters.len()
2865 }
2866}
2867
2868impl QuantumAttentionLayer {
2869 fn apply_attention_head(
2871 &self,
2872 state: &Array1<Complex64>,
2873 head: &AttentionHead,
2874 ) -> Result<Array1<Complex64>> {
2875 let mut new_state = state.clone();
2876
2877 for i in 0..head.parameter_count {
2879 let param_idx = head.parameter_start + i;
2880 if param_idx < self.parameters.len() {
2881 let angle = self.parameters[param_idx];
2882
2883 if i < head.query_qubits.len() && i < head.key_qubits.len() {
2885 let query_qubit = head.query_qubits[i];
2886 let key_qubit = head.key_qubits[i];
2887
2888 new_state =
2889 self.apply_attention_gate(&new_state, query_qubit, key_qubit, angle)?;
2890 }
2891 }
2892 }
2893
2894 Ok(new_state)
2895 }
2896
2897 fn apply_attention_gate(
2899 &self,
2900 state: &Array1<Complex64>,
2901 query_qubit: usize,
2902 key_qubit: usize,
2903 angle: f64,
2904 ) -> Result<Array1<Complex64>> {
2905 let state_size = state.len();
2906 let mut new_state = state.clone();
2907
2908 let cos_val = angle.cos();
2910 let sin_val = angle.sin();
2911
2912 for i in 0..state_size {
2913 if (i & (1 << query_qubit)) != 0 {
2914 let key_state = (i & (1 << key_qubit)) != 0;
2916 let attention_phase = if key_state {
2917 Complex64::new(cos_val, sin_val)
2918 } else {
2919 Complex64::new(cos_val, -sin_val)
2920 };
2921 new_state[i] *= attention_phase;
2922 }
2923 }
2924
2925 Ok(new_state)
2926 }
2927
2928 pub fn get_attention_structure(&self) -> &[AttentionHead] {
2930 &self.attention_structure
2931 }
2932}
2933
2934#[derive(Debug, Clone)]
2936pub struct QMLTrainingState {
2937 pub current_epoch: usize,
2939 pub current_learning_rate: f64,
2941 pub best_validation_loss: f64,
2943 pub patience_counter: usize,
2945 pub training_loss_history: Vec<f64>,
2947 pub validation_loss_history: Vec<f64>,
2949}
2950
2951impl QMLTrainingState {
2952 pub fn new() -> Self {
2954 Self {
2955 current_epoch: 0,
2956 current_learning_rate: 0.01,
2957 best_validation_loss: f64::INFINITY,
2958 patience_counter: 0,
2959 training_loss_history: Vec::new(),
2960 validation_loss_history: Vec::new(),
2961 }
2962 }
2963}
2964
2965#[derive(Debug, Clone)]
2967pub struct QMLTrainingResult {
2968 pub final_training_loss: f64,
2970 pub final_validation_loss: f64,
2972 pub best_validation_loss: f64,
2974 pub epochs_trained: usize,
2976 pub total_training_time: std::time::Duration,
2978 pub training_metrics: Vec<QMLEpochMetrics>,
2980 pub quantum_advantage_metrics: QuantumAdvantageMetrics,
2982}
2983
2984#[derive(Debug, Clone)]
2986pub struct QMLEpochMetrics {
2987 pub epoch: usize,
2989 pub training_loss: f64,
2991 pub validation_loss: f64,
2993 pub epoch_time: std::time::Duration,
2995 pub learning_rate: f64,
2997}
2998
2999#[derive(Debug, Clone, Serialize, Deserialize)]
3001pub struct QuantumAdvantageMetrics {
3002 pub quantum_volume: f64,
3004 pub classical_simulation_cost: f64,
3006 pub quantum_speedup_factor: f64,
3008 pub circuit_depth: usize,
3010 pub gate_count: usize,
3012 pub entanglement_measure: f64,
3014}
3015
3016#[derive(Debug, Clone)]
3018pub struct QMLStats {
3019 pub forward_passes: usize,
3021 pub backward_passes: usize,
3023 pub total_training_time: std::time::Duration,
3025 pub average_epoch_time: std::time::Duration,
3027 pub peak_memory_usage: usize,
3029 pub num_parameters: usize,
3031}
3032
3033impl QMLStats {
3034 pub fn new() -> Self {
3036 Self {
3037 forward_passes: 0,
3038 backward_passes: 0,
3039 total_training_time: std::time::Duration::from_secs(0),
3040 average_epoch_time: std::time::Duration::from_secs(0),
3041 peak_memory_usage: 0,
3042 num_parameters: 0,
3043 }
3044 }
3045}
3046
3047#[derive(Debug, Clone)]
3049pub struct PQCGate {
3050 pub gate_type: PQCGateType,
3052 pub qubits: Vec<usize>,
3054 pub parameter_index: Option<usize>,
3056}
3057
3058#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3060pub enum PQCGateType {
3061 SingleQubit(RotationGate),
3063 TwoQubit(TwoQubitGate),
3065}
3066
3067#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3069pub enum TwoQubitGate {
3070 CNOT,
3072 CZ,
3074 SWAP,
3076 CPhase,
3078}
3079
3080#[derive(Debug, Clone)]
3082pub struct ConvolutionalFilter {
3083 pub qubits: Vec<usize>,
3085 pub parameter_indices: Vec<usize>,
3087}
3088
3089#[derive(Debug, Clone)]
3091pub struct DenseConnection {
3092 pub qubit1: usize,
3094 pub qubit2: usize,
3096 pub parameter_index: usize,
3098}
3099
3100#[derive(Debug, Clone)]
3102pub struct LSTMGate {
3103 pub gate_type: LSTMGateType,
3105 pub parameter_start: usize,
3107 pub parameter_count: usize,
3109}
3110
3111#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3113pub enum LSTMGateType {
3114 Forget,
3116 Input,
3118 Output,
3120 Candidate,
3122}
3123
3124#[derive(Debug, Clone)]
3126pub struct AttentionHead {
3127 pub head_id: usize,
3129 pub parameter_start: usize,
3131 pub parameter_count: usize,
3133 pub query_qubits: Vec<usize>,
3135 pub key_qubits: Vec<usize>,
3137}
3138
3139#[derive(Debug, Clone, Serialize, Deserialize)]
3141pub struct QMLBenchmarkResults {
3142 pub training_times: HashMap<String, std::time::Duration>,
3144 pub final_accuracies: HashMap<String, f64>,
3146 pub convergence_rates: HashMap<String, f64>,
3148 pub memory_usage: HashMap<String, usize>,
3150 pub quantum_advantage: HashMap<String, QuantumAdvantageMetrics>,
3152 pub parameter_counts: HashMap<String, usize>,
3154 pub circuit_depths: HashMap<String, usize>,
3156 pub gate_counts: HashMap<String, usize>,
3158}
3159
3160pub struct QMLUtils;
3162
3163impl QMLUtils {
3164 pub fn generate_synthetic_data(
3166 num_samples: usize,
3167 input_dim: usize,
3168 output_dim: usize,
3169 ) -> (Vec<Array1<f64>>, Vec<Array1<f64>>) {
3170 let mut rng = thread_rng();
3171 let mut inputs = Vec::new();
3172 let mut outputs = Vec::new();
3173
3174 for _ in 0..num_samples {
3175 let input =
3176 Array1::from_vec((0..input_dim).map(|_| rng.gen_range(-1.0..1.0)).collect());
3177
3178 let output = Array1::from_vec(
3180 (0..output_dim)
3181 .map(|i| {
3182 if i < input_dim {
3183 (input[i] as f64).sin() } else {
3185 rng.gen_range(-1.0..1.0)
3186 }
3187 })
3188 .collect(),
3189 );
3190
3191 inputs.push(input);
3192 outputs.push(output);
3193 }
3194
3195 (inputs, outputs)
3196 }
3197
3198 pub fn train_test_split(
3200 inputs: Vec<Array1<f64>>,
3201 outputs: Vec<Array1<f64>>,
3202 test_ratio: f64,
3203 ) -> (
3204 Vec<(Array1<f64>, Array1<f64>)>,
3205 Vec<(Array1<f64>, Array1<f64>)>,
3206 ) {
3207 let total_samples = inputs.len();
3208 let test_samples = ((total_samples as f64) * test_ratio) as usize;
3209 let train_samples = total_samples - test_samples;
3210
3211 let mut combined: Vec<(Array1<f64>, Array1<f64>)> =
3212 inputs.into_iter().zip(outputs).collect();
3213
3214 let mut rng = thread_rng();
3216 for i in (1..combined.len()).rev() {
3217 let j = rng.gen_range(0..=i);
3218 combined.swap(i, j);
3219 }
3220
3221 let (train_data, test_data) = combined.split_at(train_samples);
3222 (train_data.to_vec(), test_data.to_vec())
3223 }
3224
3225 pub fn evaluate_accuracy(
3227 predictions: &[Array1<f64>],
3228 targets: &[Array1<f64>],
3229 threshold: f64,
3230 ) -> f64 {
3231 let mut correct = 0;
3232 let total = predictions.len();
3233
3234 for (pred, target) in predictions.iter().zip(targets.iter()) {
3235 let diff = pred - target;
3236 let mse = diff.iter().map(|x| x * x).sum::<f64>() / diff.len() as f64;
3237 if mse < threshold {
3238 correct += 1;
3239 }
3240 }
3241
3242 correct as f64 / total as f64
3243 }
3244
3245 pub fn compute_circuit_complexity(
3247 num_qubits: usize,
3248 depth: usize,
3249 gate_count: usize,
3250 ) -> HashMap<String, f64> {
3251 let mut metrics = HashMap::new();
3252
3253 let state_space_size = 2.0_f64.powi(num_qubits as i32);
3255 metrics.insert("state_space_size".to_string(), state_space_size);
3256
3257 let circuit_complexity = (depth * gate_count) as f64;
3259 metrics.insert("circuit_complexity".to_string(), circuit_complexity);
3260
3261 let classical_cost = state_space_size * gate_count as f64;
3263 metrics.insert("classical_simulation_cost".to_string(), classical_cost);
3264
3265 let quantum_advantage = classical_cost.log2() / circuit_complexity.log2();
3267 metrics.insert("quantum_advantage_estimate".to_string(), quantum_advantage);
3268
3269 metrics
3270 }
3271}
3272
3273pub fn benchmark_quantum_ml_layers(config: &QMLConfig) -> Result<QMLBenchmarkResults> {
3275 let mut results = QMLBenchmarkResults {
3276 training_times: HashMap::new(),
3277 final_accuracies: HashMap::new(),
3278 convergence_rates: HashMap::new(),
3279 memory_usage: HashMap::new(),
3280 quantum_advantage: HashMap::new(),
3281 parameter_counts: HashMap::new(),
3282 circuit_depths: HashMap::new(),
3283 gate_counts: HashMap::new(),
3284 };
3285
3286 let (inputs, outputs) =
3288 QMLUtils::generate_synthetic_data(100, config.num_qubits, config.num_qubits);
3289 let (train_data, val_data) = QMLUtils::train_test_split(inputs, outputs, 0.2);
3290
3291 let architectures = vec![
3293 QMLArchitectureType::VariationalQuantumCircuit,
3294 QMLArchitectureType::QuantumConvolutionalNN,
3295 ];
3297
3298 for architecture in architectures {
3299 let arch_name = format!("{:?}", architecture);
3300
3301 let mut arch_config = config.clone();
3303 arch_config.architecture_type = architecture;
3304
3305 let start_time = std::time::Instant::now();
3307 let mut framework = QuantumMLFramework::new(arch_config)?;
3308
3309 let training_result = framework.train(&train_data, Some(&val_data))?;
3310 let training_time = start_time.elapsed();
3311
3312 let final_accuracy = framework.evaluate(&val_data)?;
3314
3315 results
3317 .training_times
3318 .insert(arch_name.clone(), training_time);
3319 results
3320 .final_accuracies
3321 .insert(arch_name.clone(), 1.0 / (1.0 + final_accuracy)); results.convergence_rates.insert(
3323 arch_name.clone(),
3324 training_result.epochs_trained as f64 / config.training_config.epochs as f64,
3325 );
3326 results
3327 .memory_usage
3328 .insert(arch_name.clone(), framework.get_stats().peak_memory_usage);
3329 results
3330 .quantum_advantage
3331 .insert(arch_name.clone(), training_result.quantum_advantage_metrics);
3332 results.parameter_counts.insert(
3333 arch_name.clone(),
3334 framework
3335 .layers
3336 .iter()
3337 .map(|l| l.get_num_parameters())
3338 .sum(),
3339 );
3340 results.circuit_depths.insert(
3341 arch_name.clone(),
3342 framework.layers.iter().map(|l| l.get_depth()).sum(),
3343 );
3344 results.gate_counts.insert(
3345 arch_name.clone(),
3346 framework.layers.iter().map(|l| l.get_gate_count()).sum(),
3347 );
3348 }
3349
3350 Ok(results)
3351}