quantrs2_sim/qml/
benchmarks.rs1use scirs2_core::ndarray::Array1;
7use std::collections::HashMap;
8
9use super::circuit::ParameterizedQuantumCircuit;
10use super::config::{HardwareArchitecture, QMLAlgorithmType, QMLConfig};
11use super::trainer::QuantumMLTrainer;
12use crate::circuit_interfaces::InterfaceCircuit;
13use crate::error::Result;
14
15pub fn benchmark_quantum_ml_algorithms() -> Result<HashMap<String, f64>> {
17 let mut results = HashMap::new();
18
19 let algorithms = vec![
21 QMLAlgorithmType::VQE,
22 QMLAlgorithmType::QAOA,
23 QMLAlgorithmType::QCNN,
24 QMLAlgorithmType::QSVM,
25 ];
26
27 let hardware_archs = vec![
28 HardwareArchitecture::NISQ,
29 HardwareArchitecture::Superconducting,
30 HardwareArchitecture::TrappedIon,
31 ];
32
33 for &algorithm in &algorithms {
34 for &hardware in &hardware_archs {
35 let benchmark_time = benchmark_algorithm_hardware_combination(algorithm, hardware)?;
36 results.insert(format!("{:?}_{:?}", algorithm, hardware), benchmark_time);
37 }
38 }
39
40 Ok(results)
41}
42
43fn benchmark_algorithm_hardware_combination(
45 algorithm: QMLAlgorithmType,
46 hardware: HardwareArchitecture,
47) -> Result<f64> {
48 let start = std::time::Instant::now();
49
50 let config = QMLConfig {
51 algorithm_type: algorithm,
52 hardware_architecture: hardware,
53 num_qubits: 4,
54 circuit_depth: 2,
55 num_parameters: 8,
56 max_epochs: 5,
57 batch_size: 4,
58 ..Default::default()
59 };
60
61 let circuit = create_test_circuit(config.num_qubits)?;
63 let parameters = Array1::from_vec(vec![0.1; config.num_parameters]);
64 let parameter_names = (0..config.num_parameters)
65 .map(|i| format!("param_{}", i))
66 .collect();
67
68 let pqc = ParameterizedQuantumCircuit::new(circuit, parameters, parameter_names, hardware);
69
70 let mut trainer = QuantumMLTrainer::new(config, pqc, None)?;
71
72 let loss_fn = |params: &Array1<f64>| -> Result<f64> {
74 Ok(params.iter().map(|&x| x * x).sum::<f64>())
76 };
77
78 let _result = trainer.train(loss_fn)?;
79
80 Ok(start.elapsed().as_secs_f64() * 1000.0)
81}
82
83fn create_test_circuit(num_qubits: usize) -> Result<InterfaceCircuit> {
85 let circuit = InterfaceCircuit::new(num_qubits, 0);
88 Ok(circuit)
89}
90
91pub fn benchmark_gradient_methods() -> Result<HashMap<String, f64>> {
93 let mut results = HashMap::new();
94
95 let methods = vec![
96 "parameter_shift",
97 "finite_differences",
98 "automatic_differentiation",
99 "natural_gradients",
100 ];
101
102 for method in methods {
103 let benchmark_time = benchmark_gradient_method(method)?;
104 results.insert(method.to_string(), benchmark_time);
105 }
106
107 Ok(results)
108}
109
110fn benchmark_gradient_method(method: &str) -> Result<f64> {
112 let start = std::time::Instant::now();
113
114 let test_function = |params: &Array1<f64>| -> Result<f64> {
116 Ok(params
117 .iter()
118 .enumerate()
119 .map(|(i, &x)| (i as f64 + 1.0) * x * x)
120 .sum::<f64>())
121 };
122
123 let test_params = Array1::from_vec(vec![0.1, 0.2, 0.3, 0.4]);
124
125 match method {
127 "parameter_shift" => {
128 compute_parameter_shift_gradient(&test_function, &test_params)?;
129 }
130 "finite_differences" => {
131 compute_finite_difference_gradient(&test_function, &test_params)?;
132 }
133 "automatic_differentiation" => {
134 compute_autodiff_gradient(&test_function, &test_params)?;
135 }
136 "natural_gradients" => {
137 compute_natural_gradient(&test_function, &test_params)?;
138 }
139 _ => {
140 return Err(crate::error::SimulatorError::InvalidInput(format!(
141 "Unknown gradient method: {}",
142 method
143 )))
144 }
145 }
146
147 Ok(start.elapsed().as_secs_f64() * 1000.0)
148}
149
150fn compute_parameter_shift_gradient<F>(
152 function: &F,
153 parameters: &Array1<f64>,
154) -> Result<Array1<f64>>
155where
156 F: Fn(&Array1<f64>) -> Result<f64>,
157{
158 let num_params = parameters.len();
159 let mut gradient = Array1::zeros(num_params);
160 let shift = std::f64::consts::PI / 2.0;
161
162 for i in 0..num_params {
163 let mut params_plus = parameters.clone();
164 let mut params_minus = parameters.clone();
165
166 params_plus[i] += shift;
167 params_minus[i] -= shift;
168
169 let loss_plus = function(¶ms_plus)?;
170 let loss_minus = function(¶ms_minus)?;
171
172 gradient[i] = (loss_plus - loss_minus) / 2.0;
173 }
174
175 Ok(gradient)
176}
177
178fn compute_finite_difference_gradient<F>(
180 function: &F,
181 parameters: &Array1<f64>,
182) -> Result<Array1<f64>>
183where
184 F: Fn(&Array1<f64>) -> Result<f64>,
185{
186 let num_params = parameters.len();
187 let mut gradient = Array1::zeros(num_params);
188 let eps = 1e-8;
189
190 for i in 0..num_params {
191 let mut params_plus = parameters.clone();
192 params_plus[i] += eps;
193
194 let loss_plus = function(¶ms_plus)?;
195 let loss_current = function(parameters)?;
196
197 gradient[i] = (loss_plus - loss_current) / eps;
198 }
199
200 Ok(gradient)
201}
202
203fn compute_autodiff_gradient<F>(function: &F, parameters: &Array1<f64>) -> Result<Array1<f64>>
205where
206 F: Fn(&Array1<f64>) -> Result<f64>,
207{
208 compute_parameter_shift_gradient(function, parameters)
210}
211
212fn compute_natural_gradient<F>(function: &F, parameters: &Array1<f64>) -> Result<Array1<f64>>
214where
215 F: Fn(&Array1<f64>) -> Result<f64>,
216{
217 compute_parameter_shift_gradient(function, parameters)
219}
220
221pub fn benchmark_optimizers() -> Result<HashMap<String, f64>> {
223 let mut results = HashMap::new();
224
225 let optimizers = vec!["adam", "sgd", "rmsprop", "lbfgs"];
226
227 for optimizer in optimizers {
228 let benchmark_time = benchmark_optimizer(optimizer)?;
229 results.insert(optimizer.to_string(), benchmark_time);
230 }
231
232 Ok(results)
233}
234
235fn benchmark_optimizer(optimizer: &str) -> Result<f64> {
237 let start = std::time::Instant::now();
238
239 let mut params = Array1::from_vec(vec![1.0, 2.0, 3.0, 4.0]);
241 let target = Array1::<f64>::zeros(4);
242
243 for _iteration in 0..100 {
244 let gradient = ¶ms - ⌖
246
247 match optimizer {
249 "adam" => {
250 params = ¶ms - 0.01 * &gradient;
252 }
253 "sgd" => {
254 params = ¶ms - 0.01 * &gradient;
255 }
256 "rmsprop" => {
257 params = ¶ms - 0.01 * &gradient;
259 }
260 "lbfgs" => {
261 params = ¶ms - 0.01 * &gradient;
263 }
264 _ => {
265 return Err(crate::error::SimulatorError::InvalidInput(format!(
266 "Unknown optimizer: {}",
267 optimizer
268 )))
269 }
270 }
271 }
272
273 Ok(start.elapsed().as_secs_f64() * 1000.0)
274}
275
276pub fn run_comprehensive_benchmarks() -> Result<HashMap<String, HashMap<String, f64>>> {
278 let mut all_results = HashMap::new();
279
280 all_results.insert("algorithms".to_string(), benchmark_quantum_ml_algorithms()?);
281 all_results.insert("gradients".to_string(), benchmark_gradient_methods()?);
282 all_results.insert("optimizers".to_string(), benchmark_optimizers()?);
283
284 Ok(all_results)
285}