quantrs2_ml/tensorflow_compatibility/
spsadifferentiator_traits.rs1use crate::error::{MLError, Result};
13use crate::simulator_backends::{DynamicCircuit, Observable, SimulationResult, SimulatorBackend};
14use quantrs2_circuit::prelude::*;
15use quantrs2_core::prelude::*;
16
17use super::functions::Differentiator;
18use super::types::SPSADifferentiator;
19
20impl Default for SPSADifferentiator {
21 fn default() -> Self {
22 Self::new()
23 }
24}
25
26impl Differentiator for SPSADifferentiator {
27 fn differentiate(
28 &self,
29 circuit: &DynamicCircuit,
30 parameters: &[f64],
31 observable: &Observable,
32 backend: &dyn SimulatorBackend,
33 ) -> Result<Vec<f64>> {
34 let n_params = parameters.len();
35 let mut gradients = vec![0.0; n_params];
36 for _ in 0..self.num_samples {
37 let delta: Vec<f64> = (0..n_params)
38 .map(|_| if fastrand::bool() { 1.0 } else { -1.0 })
39 .collect();
40 let params_plus: Vec<f64> = parameters
41 .iter()
42 .zip(delta.iter())
43 .map(|(p, d)| p + self.epsilon * d)
44 .collect();
45 let params_minus: Vec<f64> = parameters
46 .iter()
47 .zip(delta.iter())
48 .map(|(p, d)| p - self.epsilon * d)
49 .collect();
50 let exp_plus = backend.expectation_value(circuit, ¶ms_plus, observable)?;
51 let exp_minus = backend.expectation_value(circuit, ¶ms_minus, observable)?;
52 let diff = exp_plus - exp_minus;
53 for (i, d) in delta.iter().enumerate() {
54 gradients[i] += diff / (2.0 * self.epsilon * d);
55 }
56 }
57 for g in &mut gradients {
58 *g /= self.num_samples as f64;
59 }
60 Ok(gradients)
61 }
62 fn name(&self) -> &str {
63 "SPSA"
64 }
65}