quantrs2_ml/tensorflow_compatibility/
spsadifferentiator_traits.rs

1//! # SPSADifferentiator - Trait Implementations
2//!
3//! This module contains trait implementations for `SPSADifferentiator`.
4//!
5//! ## Implemented Traits
6//!
7//! - `Default`
8//! - `Differentiator`
9//!
10//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
11
12use 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, &params_plus, observable)?;
51            let exp_minus = backend.expectation_value(circuit, &params_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}