1pub mod advanced_algorithms;
8pub mod encoding;
9pub mod generative_adversarial;
10pub mod layers;
11pub mod nlp;
12pub mod reinforcement_learning;
13pub mod simulator;
14pub mod training;
15
16pub mod quantum_contrastive;
18pub mod quantum_memory_networks;
19pub mod quantum_meta_learning;
20pub mod quantum_reservoir;
21pub mod quantum_transformer;
22
23pub mod quantum_boltzmann;
25pub mod quantum_federated;
26
27pub use advanced_algorithms::{
29 FeatureMapType, QMLMetrics, QuantumEnsemble, QuantumKernel, QuantumKernelConfig, QuantumSVM,
30 QuantumTransferLearning, TransferLearningConfig, VotingStrategy,
31};
32
33pub use quantum_contrastive::{
35 QuantumAugmentation, QuantumContrastiveConfig, QuantumContrastiveLearner,
36};
37pub use quantum_memory_networks::{MemoryInitStrategy, QuantumMemoryConfig, QuantumMemoryNetwork};
38pub use quantum_meta_learning::{
39 QuantumMAML, QuantumMetaLearningConfig, QuantumReptile, QuantumTask,
40};
41pub use quantum_reservoir::{QuantumReservoirComputer, QuantumReservoirConfig};
42pub use quantum_transformer::{QuantumAttention, QuantumTransformer, QuantumTransformerConfig};
43
44pub use quantum_boltzmann::{DeepQuantumBoltzmannMachine, QRBMConfig, QuantumRBM};
46pub use quantum_federated::{AggregationStrategy, QuantumFederatedConfig, QuantumFederatedServer};
47
48use crate::{
49 error::{QuantRS2Error, QuantRS2Result},
50 gate::GateOp,
51 qubit::QubitId,
52};
53use scirs2_core::ndarray::{Array1, Array2};
54use scirs2_core::Complex64;
55
56pub use layers::Parameter;
58
59pub trait QMLLayer: Send + Sync {
61 fn num_qubits(&self) -> usize;
63
64 fn parameters(&self) -> &[Parameter];
66
67 fn parameters_mut(&mut self) -> &mut [Parameter];
69
70 fn set_parameters(&mut self, values: &[f64]) -> QuantRS2Result<()> {
72 if values.len() != self.parameters().len() {
73 return Err(QuantRS2Error::InvalidInput(format!(
74 "Expected {} parameters, got {}",
75 self.parameters().len(),
76 values.len()
77 )));
78 }
79
80 for (param, &value) in self.parameters_mut().iter_mut().zip(values.iter()) {
81 param.value = value;
82 }
83
84 Ok(())
85 }
86
87 fn gates(&self) -> Vec<Box<dyn GateOp>>;
89
90 fn compute_gradients(
92 &self,
93 state: &Array1<Complex64>,
94 loss_gradient: &Array1<Complex64>,
95 ) -> QuantRS2Result<Vec<f64>>;
96
97 fn name(&self) -> &str;
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub enum EncodingStrategy {
104 Amplitude,
106 Angle,
108 IQP,
110 Basis,
112}
113
114#[derive(Debug, Clone)]
116pub struct QMLConfig {
117 pub num_qubits: usize,
119 pub num_layers: usize,
121 pub encoding: EncodingStrategy,
123 pub entanglement: EntanglementPattern,
125 pub data_reuploading: bool,
127}
128
129impl Default for QMLConfig {
130 fn default() -> Self {
131 Self {
132 num_qubits: 4,
133 num_layers: 2,
134 encoding: EncodingStrategy::Angle,
135 entanglement: EntanglementPattern::Full,
136 data_reuploading: false,
137 }
138 }
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq)]
143pub enum EntanglementPattern {
144 None,
146 Linear,
148 Circular,
150 Full,
152 Alternating,
154}
155
156pub struct QMLCircuit {
158 config: QMLConfig,
160 layers: Vec<Box<dyn QMLLayer>>,
162 num_parameters: usize,
164}
165
166impl QMLCircuit {
167 pub fn new(config: QMLConfig) -> Self {
169 Self {
170 config,
171 layers: Vec::new(),
172 num_parameters: 0,
173 }
174 }
175
176 pub fn add_layer(&mut self, layer: Box<dyn QMLLayer>) -> QuantRS2Result<()> {
178 if layer.num_qubits() != self.config.num_qubits {
179 return Err(QuantRS2Error::InvalidInput(format!(
180 "Layer has {} qubits, circuit has {}",
181 layer.num_qubits(),
182 self.config.num_qubits
183 )));
184 }
185
186 self.num_parameters += layer.parameters().len();
187 self.layers.push(layer);
188 Ok(())
189 }
190
191 pub fn parameters(&self) -> Vec<&Parameter> {
193 self.layers
194 .iter()
195 .flat_map(|layer| layer.parameters().iter())
196 .collect()
197 }
198
199 pub fn set_parameters(&mut self, values: &[f64]) -> QuantRS2Result<()> {
201 if values.len() != self.num_parameters {
202 return Err(QuantRS2Error::InvalidInput(format!(
203 "Expected {} parameters, got {}",
204 self.num_parameters,
205 values.len()
206 )));
207 }
208
209 let mut offset = 0;
210 for layer in &mut self.layers {
211 let layer_params = layer.parameters().len();
212 layer.set_parameters(&values[offset..offset + layer_params])?;
213 offset += layer_params;
214 }
215
216 Ok(())
217 }
218
219 pub fn gates(&self) -> Vec<Box<dyn GateOp>> {
221 self.layers.iter().flat_map(|layer| layer.gates()).collect()
222 }
223
224 pub fn compute_gradients(
226 &self,
227 state: &Array1<Complex64>,
228 loss_gradient: &Array1<Complex64>,
229 ) -> QuantRS2Result<Vec<f64>> {
230 let mut all_gradients = Vec::new();
231
232 for layer in &self.layers {
233 let layer_grads = layer.compute_gradients(state, loss_gradient)?;
234 all_gradients.extend(layer_grads);
235 }
236
237 Ok(all_gradients)
238 }
239}
240
241pub fn create_entangling_gates(
243 num_qubits: usize,
244 pattern: EntanglementPattern,
245) -> Vec<(QubitId, QubitId)> {
246 match pattern {
247 EntanglementPattern::None => vec![],
248
249 EntanglementPattern::Linear => (0..num_qubits - 1)
250 .map(|i| (QubitId(i as u32), QubitId((i + 1) as u32)))
251 .collect(),
252
253 EntanglementPattern::Circular => {
254 let mut gates = vec![];
255 for i in 0..num_qubits {
256 gates.push((QubitId(i as u32), QubitId(((i + 1) % num_qubits) as u32)));
257 }
258 gates
259 }
260
261 EntanglementPattern::Full => {
262 let mut gates = vec![];
263 for i in 0..num_qubits {
264 for j in i + 1..num_qubits {
265 gates.push((QubitId(i as u32), QubitId(j as u32)));
266 }
267 }
268 gates
269 }
270
271 EntanglementPattern::Alternating => {
272 let mut gates = vec![];
273 for i in (0..num_qubits - 1).step_by(2) {
275 gates.push((QubitId(i as u32), QubitId((i + 1) as u32)));
276 }
277 for i in (1..num_qubits - 1).step_by(2) {
279 gates.push((QubitId(i as u32), QubitId((i + 1) as u32)));
280 }
281 gates
282 }
283 }
284}
285
286pub fn quantum_fisher_information(circuit: &mut QMLCircuit) -> QuantRS2Result<Array2<f64>> {
300 let num_params = circuit.num_parameters;
301 let mut fisher = Array2::zeros((num_params, num_params));
302 if num_params == 0 {
303 return Ok(fisher);
304 }
305
306 let num_qubits = circuit.config.num_qubits;
307 let base_params: Vec<f64> = circuit.parameters().iter().map(|p| p.value).collect();
308
309 let epsilon = 1e-6;
311 let dim = 1usize << num_qubits;
312
313 circuit.set_parameters(&base_params)?;
315 let psi = simulator::simulate(num_qubits, &circuit.gates())?;
316
317 let mut derivatives: Vec<Array1<Complex64>> = Vec::with_capacity(num_params);
319 for i in 0..num_params {
320 let mut plus = base_params.clone();
321 plus[i] += epsilon;
322 circuit.set_parameters(&plus)?;
323 let psi_plus = simulator::simulate(num_qubits, &circuit.gates())?;
324
325 let mut minus = base_params.clone();
326 minus[i] -= epsilon;
327 circuit.set_parameters(&minus)?;
328 let psi_minus = simulator::simulate(num_qubits, &circuit.gates())?;
329
330 let mut deriv = Array1::zeros(dim);
331 for k in 0..dim {
332 deriv[k] = (psi_plus[k] - psi_minus[k]) / Complex64::new(2.0 * epsilon, 0.0);
333 }
334 derivatives.push(deriv);
335 }
336
337 circuit.set_parameters(&base_params)?;
339
340 let psi_dot_deriv: Vec<Complex64> = derivatives
342 .iter()
343 .map(|d| {
344 psi.iter()
345 .zip(d.iter())
346 .map(|(p, di)| p.conj() * di)
347 .sum::<Complex64>()
348 })
349 .collect();
350
351 for i in 0..num_params {
353 for j in i..num_params {
354 let overlap: Complex64 = derivatives[i]
355 .iter()
356 .zip(derivatives[j].iter())
357 .map(|(di, dj)| di.conj() * dj)
358 .sum();
359 let correction = psi_dot_deriv[i].conj() * psi_dot_deriv[j];
360 let value = 4.0 * (overlap - correction).re;
361 fisher[(i, j)] = value;
362 fisher[(j, i)] = value;
363 }
364 }
365
366 Ok(fisher)
367}
368
369pub fn natural_gradient(
377 gradients: &[f64],
378 fisher: &Array2<f64>,
379 regularization: f64,
380) -> QuantRS2Result<Vec<f64>> {
381 let n = gradients.len();
382 if n == 0 {
383 return Ok(Vec::new());
384 }
385 if fisher.nrows() != n || fisher.ncols() != n {
386 return Err(QuantRS2Error::InvalidInput(format!(
387 "Fisher matrix is {}×{} but gradient has length {n}",
388 fisher.nrows(),
389 fisher.ncols()
390 )));
391 }
392
393 let mut regularized = fisher.clone();
395 for i in 0..n {
396 regularized[(i, i)] += regularization;
397 }
398
399 let grad = Array1::from_vec(gradients.to_vec());
400
401 if n == 1 {
403 let denom = regularized[(0, 0)];
404 if denom.abs() < 1e-14 {
405 return Err(QuantRS2Error::InvalidInput(
406 "regularized Fisher matrix is singular".to_string(),
407 ));
408 }
409 return Ok(vec![grad[0] / denom]);
410 }
411
412 let inverse = scirs2_linalg::inv(®ularized.view(), None).map_err(|e| {
413 QuantRS2Error::ComputationError(format!("natural gradient solve failed: {e:?}"))
414 })?;
415 let natural = inverse.dot(&grad);
416 Ok(natural.to_vec())
417}
418
419#[cfg(test)]
420mod tests {
421 use super::*;
422
423 #[test]
424 fn test_entanglement_patterns() {
425 let linear = create_entangling_gates(4, EntanglementPattern::Linear);
426 assert_eq!(linear.len(), 3);
427 assert_eq!(linear[0], (QubitId(0), QubitId(1)));
428
429 let circular = create_entangling_gates(4, EntanglementPattern::Circular);
430 assert_eq!(circular.len(), 4);
431 assert_eq!(circular[3], (QubitId(3), QubitId(0)));
432
433 let full = create_entangling_gates(3, EntanglementPattern::Full);
434 assert_eq!(full.len(), 3); let none = create_entangling_gates(4, EntanglementPattern::None);
437 assert_eq!(none.len(), 0);
438 }
439
440 #[test]
441 fn test_qml_circuit() {
442 let config = QMLConfig {
443 num_qubits: 2,
444 num_layers: 1,
445 ..Default::default()
446 };
447
448 let circuit = QMLCircuit::new(config);
449 assert_eq!(circuit.num_parameters, 0);
450 }
451
452 #[test]
453 fn test_natural_gradient_solves_system_not_passthrough() {
454 let fisher =
458 Array2::from_shape_vec((2, 2), vec![2.0, 0.5, 0.5, 3.0]).expect("fisher matrix");
459 let gradients = vec![1.0, 1.0];
460 let reg = 0.0;
461
462 let g_nat = natural_gradient(&gradients, &fisher, reg).expect("natural gradient");
463
464 let recon0 = fisher[(0, 0)] * g_nat[0] + fisher[(0, 1)] * g_nat[1];
466 let recon1 = fisher[(1, 0)] * g_nat[0] + fisher[(1, 1)] * g_nat[1];
467 assert!((recon0 - gradients[0]).abs() < 1e-9);
468 assert!((recon1 - gradients[1]).abs() < 1e-9);
469
470 assert!(
472 (g_nat[0] - gradients[0]).abs() > 1e-6 || (g_nat[1] - gradients[1]).abs() > 1e-6,
473 "natural gradient must differ from raw gradient for non-identity Fisher"
474 );
475 }
476
477 #[test]
478 fn test_natural_gradient_identity_fisher_is_passthrough() {
479 let fisher = Array2::zeros((3, 3));
482 let gradients = vec![0.4, -1.2, 0.7];
483 let g_nat = natural_gradient(&gradients, &fisher, 1.0).expect("natural gradient");
484 for (a, b) in g_nat.iter().zip(gradients.iter()) {
485 assert!((a - b).abs() < 1e-12);
486 }
487 }
488
489 #[test]
490 fn test_quantum_fisher_information_is_nonzero_for_parameterized_circuit() {
491 let config = QMLConfig {
494 num_qubits: 2,
495 num_layers: 1,
496 ..Default::default()
497 };
498 let mut circuit = QMLCircuit::new(config);
499 let layer = layers::RotationLayer::uniform(2, 'Y').expect("rotation layer");
500 circuit.add_layer(Box::new(layer)).expect("add layer");
501 circuit.set_parameters(&[0.5, 1.1]).expect("set parameters");
503
504 let fisher = quantum_fisher_information(&mut circuit).expect("fisher");
505 assert_eq!(fisher.shape(), &[2, 2]);
506 let max_abs = fisher.iter().fold(0.0_f64, |acc, &v| acc.max(v.abs()));
507 assert!(
508 max_abs > 1e-6,
509 "Fisher information must be non-zero for a parameterized circuit, got max {max_abs}"
510 );
511 assert!(fisher[(0, 0)] > 1e-3 && fisher[(1, 1)] > 1e-3);
513 }
514}