1use quantrs2_circuit::builder::{Circuit, Simulator};
7use quantrs2_core::{error::QuantRS2Result, qubit::QubitId};
8use scirs2_core::random::ChaCha8Rng;
9use scirs2_core::random::{Rng, SeedableRng};
10use std::time::{Duration, Instant};
11
12use crate::optimized_simulator::OptimizedSimulator;
13use crate::optimized_simulator_chunked::OptimizedSimulatorChunked;
14use crate::optimized_simulator_simple::OptimizedSimulatorSimple;
15use crate::statevector::StateVectorSimulator;
16
17#[derive(Debug, Clone)]
19pub struct BenchmarkResult {
20 pub simulator_name: String,
22 pub num_qubits: usize,
24 pub num_gates: usize,
26 pub duration: Duration,
28 pub notes: Option<String>,
30 pub peak_memory: Option<usize>,
32}
33
34impl BenchmarkResult {
35 pub fn new(
37 simulator_name: &str,
38 num_qubits: usize,
39 num_gates: usize,
40 duration: Duration,
41 notes: Option<String>,
42 peak_memory: Option<usize>,
43 ) -> Self {
44 Self {
45 simulator_name: simulator_name.to_string(),
46 num_qubits,
47 num_gates,
48 duration,
49 notes,
50 peak_memory,
51 }
52 }
53
54 pub fn format(&self) -> String {
56 let duration_ms = self.duration.as_millis();
57 let rate = if duration_ms > 0 {
58 self.num_gates as f64 / (duration_ms as f64 / 1000.0)
59 } else {
60 f64::INFINITY
61 };
62
63 let notes = if let Some(ref notes) = self.notes {
64 format!(" ({notes})")
65 } else {
66 String::new()
67 };
68
69 let memory_str = if let Some(mem) = self.peak_memory {
70 format!(", Memory: {:.2} MB", mem as f64 / (1024.0 * 1024.0))
71 } else {
72 String::new()
73 };
74
75 format!(
76 "Simulator: {}{}\n Qubits: {}\n Gates: {}\n Time: {} ms\n Rate: {:.2} gates/s{}",
77 self.simulator_name,
78 notes,
79 self.num_qubits,
80 self.num_gates,
81 duration_ms,
82 rate,
83 memory_str
84 )
85 }
86}
87
88pub fn run_benchmark<S, const N: usize>(
90 name: &str,
91 simulator: &S,
92 circuit: &Circuit<N>,
93 notes: Option<String>,
94) -> QuantRS2Result<BenchmarkResult>
95where
96 S: Simulator<N>,
97{
98 let num_qubits = N;
99 let num_gates = circuit.gates().len();
100
101 let start = Instant::now();
102 let _result = simulator.run(circuit)?;
103 let duration = start.elapsed();
104
105 Ok(BenchmarkResult::new(
106 name, num_qubits, num_gates, duration, notes, None,
107 ))
108}
109
110pub fn compare_simulators<const N: usize>(circuit: &Circuit<N>) -> Vec<BenchmarkResult> {
112 let mut results = Vec::new();
113
114 if N <= 24 {
116 let standard_sim = StateVectorSimulator::new();
118 if let Ok(result) = run_benchmark("Standard Simulator", &standard_sim, circuit, None) {
119 results.push(result);
120 }
121 }
122
123 let simple_opt_sim = OptimizedSimulatorSimple::new();
125 if let Ok(result) = run_benchmark("Simple Optimized", &simple_opt_sim, circuit, None) {
126 results.push(result);
127 }
128
129 let chunked_sim = OptimizedSimulatorChunked::new();
131 if let Ok(result) = run_benchmark("Chunked Optimized", &chunked_sim, circuit, None) {
132 results.push(result);
133 }
134
135 let optimized_sim = OptimizedSimulator::new();
137 if let Ok(result) = run_benchmark(
138 "Full Optimized",
139 &optimized_sim,
140 circuit,
141 Some("Auto-selection".to_string()),
142 ) {
143 results.push(result);
144 }
145
146 if N <= 20 {
148 let memory_efficient_sim = OptimizedSimulator::memory_efficient();
149 if let Ok(result) = run_benchmark(
150 "Memory Efficient",
151 &memory_efficient_sim,
152 circuit,
153 Some("Low memory".to_string()),
154 ) {
155 results.push(result);
156 }
157 }
158
159 results
160}
161
162pub fn generate_benchmark_circuit<const N: usize>(
164 num_gates: usize,
165 two_qubit_ratio: f64,
166) -> Circuit<N> {
167 let mut circuit = Circuit::new();
168 let mut rng = ChaCha8Rng::seed_from_u64(42); for _ in 0..num_gates {
171 let is_two_qubit = rng.random::<f64>() < two_qubit_ratio;
173
174 if is_two_qubit && N > 1 {
175 let qubit1 = QubitId::new(rng.random_range(0..N as u32));
177 let mut qubit2 = QubitId::new(rng.random_range(0..N as u32));
178 while qubit2 == qubit1 {
179 qubit2 = QubitId::new(rng.random_range(0..N as u32));
180 }
181
182 let gate_type = rng.random_range(0..3);
184 match gate_type {
185 0 => {
186 let _ = circuit.cnot(qubit1, qubit2);
187 }
188 1 => {
189 let _ = circuit.cz(qubit1, qubit2);
190 }
191 _ => {
192 let _ = circuit.swap(qubit1, qubit2);
193 }
194 }
195 } else {
196 let qubit = QubitId::new(rng.random_range(0..N as u32));
198
199 let gate_type = rng.random_range(0..7);
201 match gate_type {
202 0 => {
203 let _ = circuit.h(qubit);
204 }
205 1 => {
206 let _ = circuit.x(qubit);
207 }
208 2 => {
209 let _ = circuit.y(qubit);
210 }
211 3 => {
212 let _ = circuit.z(qubit);
213 }
214 4 => {
215 let _ = circuit.s(qubit);
216 }
217 5 => {
218 let _ = circuit.t(qubit);
219 }
220 _ => {
221 let angle = rng.random_range(0.0..std::f64::consts::TAU);
223 let rotation_type = rng.random_range(0..3);
224 match rotation_type {
225 0 => {
226 let _ = circuit.rx(qubit, angle);
227 }
228 1 => {
229 let _ = circuit.ry(qubit, angle);
230 }
231 _ => {
232 let _ = circuit.rz(qubit, angle);
233 }
234 }
235 }
236 }
237 }
238 }
239
240 circuit
241}
242
243pub fn run_benchmark_suite() {
245 println!("=== Quantrs Simulator Benchmark Suite ===");
246 println!("Testing various circuit sizes with different simulator implementations");
247 println!();
248
249 benchmark_circuit_size::<16>("Small", 16, 100, 0.3);
251
252 benchmark_circuit_size::<20>("Medium", 20, 50, 0.3);
254
255 benchmark_circuit_size::<25>("Large", 25, 20, 0.2);
257
258 benchmark_large_circuit::<28>("Very Large", 28, 10, 0.1);
260}
261
262fn benchmark_circuit_size<const N: usize>(
264 size_name: &str,
265 max_qubits: usize,
266 gates_per_qubit: usize,
267 two_qubit_ratio: f64,
268) {
269 println!("\n=== {size_name} Circuit Tests (up to {max_qubits} qubits) ===");
270
271 if N < max_qubits {
273 println!("Cannot benchmark this size - const generic N is too small");
274 return;
275 }
276
277 for qubits in [
279 max_qubits / 4,
280 max_qubits / 2,
281 (3 * max_qubits) / 4,
282 max_qubits,
283 ] {
284 let num_gates = qubits * gates_per_qubit;
285 println!("\nCircuit with {qubits} qubits and {num_gates} gates:");
286
287 let circuit = generate_benchmark_circuit::<N>(num_gates, two_qubit_ratio);
289
290 let results = compare_simulators(&circuit);
292
293 for result in &results {
295 println!("{}\n", result.format());
296 }
297 }
298}
299
300fn benchmark_large_circuit<const N: usize>(
302 size_name: &str,
303 max_qubits: usize,
304 gates_per_qubit: usize,
305 two_qubit_ratio: f64,
306) {
307 println!("\n=== {size_name} Circuit Tests ({max_qubits} qubits) ===");
308
309 if N < max_qubits {
311 println!("Cannot benchmark this size - const generic N is too small");
312 return;
313 }
314
315 let num_gates = max_qubits * gates_per_qubit;
316 println!("\nCircuit with {max_qubits} qubits and {num_gates} gates:");
317
318 let circuit = generate_benchmark_circuit::<N>(num_gates, two_qubit_ratio);
320
321 let mut results = Vec::new();
323
324 let chunked_sim = OptimizedSimulatorChunked::new();
326 if let Ok(result) = run_benchmark("Chunked Optimized", &chunked_sim, &circuit, None) {
327 results.push(result);
328 }
329
330 let optimized_sim = OptimizedSimulator::new();
332 if let Ok(result) = run_benchmark(
333 "Full Optimized",
334 &optimized_sim,
335 &circuit,
336 Some("Auto-selection".to_string()),
337 ) {
338 results.push(result);
339 }
340
341 for result in &results {
343 println!("{}\n", result.format());
344 }
345}
346
347#[cfg(test)]
348mod tests {
349 use super::*;
350
351 #[test]
352 #[ignore] fn benchmark_small_circuit() {
354 const QUBITS: usize = 16;
355 let circuit = generate_benchmark_circuit::<QUBITS>(100, 0.3);
356
357 let results = compare_simulators(&circuit);
358
359 for result in &results {
360 println!("{}\n", result.format());
361 }
362 }
363
364 #[test]
365 #[ignore] fn benchmark_medium_circuit() {
367 const QUBITS: usize = 20;
368 let circuit = generate_benchmark_circuit::<QUBITS>(50, 0.3);
369
370 let results = compare_simulators(&circuit);
371
372 for result in &results {
373 println!("{}\n", result.format());
374 }
375 }
376
377 #[test]
378 #[ignore] fn benchmark_large_circuit() {
380 const QUBITS: usize = 25;
381 let circuit = generate_benchmark_circuit::<QUBITS>(20, 0.2);
382
383 let mut results = Vec::new();
385
386 let chunked_sim = OptimizedSimulatorChunked::new();
388 if let Ok(result) = run_benchmark("Chunked Optimized", &chunked_sim, &circuit, None) {
389 results.push(result);
390 }
391
392 let optimized_sim = OptimizedSimulator::new();
393 if let Ok(result) = run_benchmark(
394 "Full Optimized",
395 &optimized_sim,
396 &circuit,
397 Some("Auto-selection".to_string()),
398 ) {
399 results.push(result);
400 }
401
402 for result in &results {
403 println!("{}\n", result.format());
404 }
405 }
406
407 #[test]
408 #[ignore] fn run_full_benchmark_suite() {
410 run_benchmark_suite();
411 }
412}