use super::{
circuits::ParametricCircuit,
hardware::HardwareConfig,
noise::NoiseMitigationConfig,
objectives::{ObjectiveEvaluator, ObjectiveFunction, ObjectiveResult},
statistical::VQAStatistics,
};
use crate::DeviceResult;
use scirs2_core::ndarray::Array1;
use scirs2_core::random::prelude::*;
use std::collections::HashMap;
use std::time::{Duration, Instant};
#[derive(Debug, Clone)]
pub struct VQAExecutorConfig {
pub max_iterations: usize,
pub tolerance: f64,
pub hardware: HardwareConfig,
pub noise_mitigation: NoiseMitigationConfig,
pub optimizer: OptimizerConfig,
}
#[derive(Debug, Clone)]
pub struct OptimizerConfig {
pub optimizer_type: OptimizerType,
pub learning_rate: f64,
pub parameters: HashMap<String, f64>,
}
#[derive(Debug, Clone)]
pub enum OptimizerType {
GradientDescent,
Adam,
LBFGSB,
COBYLA,
}
impl Default for VQAExecutorConfig {
fn default() -> Self {
Self {
max_iterations: 1000,
tolerance: 1e-6,
hardware: HardwareConfig::default(),
noise_mitigation: NoiseMitigationConfig::default(),
optimizer: OptimizerConfig::default(),
}
}
}
impl Default for OptimizerConfig {
fn default() -> Self {
Self {
optimizer_type: OptimizerType::Adam,
learning_rate: 0.01,
parameters: HashMap::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct VQAResult {
pub optimal_parameters: Vec<f64>,
pub best_value: f64,
pub iterations: usize,
pub execution_time: Duration,
pub converged: bool,
pub statistics: VQAStatistics,
pub history: Vec<f64>,
}
#[derive(Debug)]
pub struct VQAExecutor {
pub config: VQAExecutorConfig,
}
impl VQAExecutor {
pub fn new(
config: super::config::VQAConfig,
_calibration_manager: crate::calibration::CalibrationManager,
_device: Option<String>,
) -> Self {
Self {
config: VQAExecutorConfig::default(),
}
}
pub const fn with_config(config: VQAExecutorConfig) -> Self {
Self { config }
}
pub fn execute(
&self,
circuit: &mut ParametricCircuit,
objective: &ObjectiveEvaluator,
) -> DeviceResult<VQAResult> {
let start_time = Instant::now();
let mut best_value = f64::INFINITY;
let mut best_params = circuit.parameters.clone();
let mut history = Vec::new();
let mut converged = false;
for iteration in 0..self.config.max_iterations {
let result = objective.evaluate(&Array1::from_vec(circuit.parameters.clone()))?;
history.push(result.value);
if result.value < best_value {
best_value = result.value;
best_params.clone_from(&circuit.parameters);
}
if result.value.abs() < self.config.tolerance {
converged = true;
break;
}
self.update_parameters(circuit, &result)?;
}
let execution_time = start_time.elapsed();
let statistics = super::statistical::analyze_convergence(&history);
Ok(VQAResult {
optimal_parameters: best_params,
best_value,
iterations: history.len(),
execution_time,
converged,
statistics,
history,
})
}
fn update_parameters(
&self,
circuit: &mut ParametricCircuit,
_result: &ObjectiveResult,
) -> DeviceResult<()> {
use scirs2_core::random::prelude::*;
let mut rng = thread_rng();
for param in &mut circuit.parameters {
*param += rng.random_range(-0.1..0.1) * self.config.optimizer.learning_rate;
}
Ok(())
}
}