use crate::circuit_interfaces::{InterfaceCircuit, InterfaceGate, InterfaceGateType};
use crate::error::Result;
use scirs2_core::ndarray::Array1;
use scirs2_core::Complex64;
use std::collections::HashMap;
use super::types::{
ArithmeticPrecision, FPGAConfig, FPGADeviceInfo, FPGAPlatform, FPGAQuantumSimulator, ModuleType,
};
pub fn benchmark_fpga_acceleration() -> Result<HashMap<String, f64>> {
let mut results = HashMap::new();
let configs = vec![
FPGAConfig {
platform: FPGAPlatform::Simulation,
num_processing_units: 8,
clock_frequency: 300.0,
..Default::default()
},
FPGAConfig {
platform: FPGAPlatform::Simulation,
num_processing_units: 16,
clock_frequency: 400.0,
..Default::default()
},
FPGAConfig {
platform: FPGAPlatform::Simulation,
num_processing_units: 32,
clock_frequency: 500.0,
enable_pipelining: true,
..Default::default()
},
];
let mut total_gates: u64 = 0;
let mut total_exec_seconds = 0.0;
let compile_start = std::time::Instant::now();
let mut simulators_built = 0u32;
for (i, config) in configs.into_iter().enumerate() {
let build_start = std::time::Instant::now();
let mut simulator = FPGAQuantumSimulator::new(config)?;
let _build_time = build_start.elapsed();
simulators_built += 1;
let mut circuit = InterfaceCircuit::new(10, 0);
circuit.add_gate(InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]));
circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![0, 1]));
circuit.add_gate(InterfaceGate::new(InterfaceGateType::RY(0.5), vec![2]));
circuit.add_gate(InterfaceGate::new(InterfaceGateType::CZ, vec![1, 2]));
let gates_per_run = circuit.gates.len() as u64;
let start = std::time::Instant::now();
for _ in 0..10 {
let _result = simulator.execute_circuit(&circuit)?;
}
let elapsed = start.elapsed();
total_exec_seconds += elapsed.as_secs_f64();
total_gates += gates_per_run * 10;
let time = elapsed.as_secs_f64() * 1000.0;
results.insert(format!("fpga_config_{i}"), time);
let stats = simulator.get_stats();
results.insert(
format!("fpga_config_{i}_operations"),
stats.total_gate_operations as f64,
);
results.insert(
format!("fpga_config_{i}_avg_gate_time"),
stats.avg_gate_time,
);
results.insert(
format!("fpga_config_{i}_utilization"),
stats.fpga_utilization,
);
let performance_metrics = stats.get_performance_metrics();
for (key, value) in performance_metrics {
results.insert(format!("fpga_config_{i}_{key}"), value);
}
}
let _ = simulators_built;
results.insert(
"kernel_compilation_time".to_string(),
compile_start.elapsed().as_secs_f64() * 1000.0,
);
let throughput = if total_exec_seconds > 0.0 {
total_gates as f64 / total_exec_seconds
} else {
0.0
};
results.insert("gate_execution_throughput".to_string(), throughput);
let reference_bandwidth = FPGADeviceInfo::for_platform(FPGAPlatform::Simulation)
.memory_interfaces
.first()
.map_or(0.0, |iface| iface.bandwidth);
results.insert("memory_transfer_bandwidth".to_string(), reference_bandwidth);
Ok(results)
}
#[cfg(test)]
mod tests {
use super::super::types::FPGAStats;
use super::*;
use approx::assert_abs_diff_eq;
fn sim_config() -> FPGAConfig {
FPGAConfig {
platform: FPGAPlatform::Simulation,
..Default::default()
}
}
#[test]
fn test_no_real_fpga_even_for_board_platform() {
let config = FPGAConfig::default(); let simulator =
FPGAQuantumSimulator::new(config).expect("CPU simulation always constructs");
assert!(!simulator.is_fpga_available());
}
#[test]
fn test_simulation_platform_creation() {
let simulator = FPGAQuantumSimulator::new(sim_config());
assert!(simulator.is_ok());
assert!(!simulator
.expect("simulation platform should construct")
.is_fpga_available());
}
#[test]
fn test_device_info_reference_specs() {
let device_info = FPGADeviceInfo::for_platform(FPGAPlatform::IntelStratix10);
assert_eq!(device_info.platform, FPGAPlatform::IntelStratix10);
assert_eq!(device_info.logic_elements, 2_800_000);
assert_eq!(device_info.dsp_blocks, 5760);
}
#[test]
fn test_processing_unit_creation() {
let config = sim_config();
let device_info = FPGADeviceInfo::for_platform(config.platform);
let units = FPGAQuantumSimulator::create_processing_units(&config, &device_info)
.expect("should create processing units successfully");
assert_eq!(units.len(), config.num_processing_units);
assert!(!units[0].supported_gates.is_empty());
assert!(!units[0].pipeline_stages.is_empty());
}
#[test]
fn test_hdl_generation() {
let mut simulator = FPGAQuantumSimulator::new(sim_config())
.expect("should create FPGA simulator for HDL generation test");
assert!(simulator.hdl_modules.contains_key("single_qubit_gate"));
assert!(simulator.hdl_modules.contains_key("two_qubit_gate"));
let single_qubit_module = &simulator.hdl_modules["single_qubit_gate"];
assert!(!single_qubit_module.hdl_code.is_empty());
assert_eq!(single_qubit_module.module_type, ModuleType::SingleQubitGate);
assert!(simulator.hdl_modules["two_qubit_gate"].hdl_code.is_empty());
}
#[test]
fn test_circuit_execution() {
let mut simulator = FPGAQuantumSimulator::new(sim_config())
.expect("should create FPGA simulator for circuit execution test");
let mut circuit = InterfaceCircuit::new(2, 0);
circuit.add_gate(InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]));
let result = simulator.execute_circuit(&circuit);
assert!(result.is_ok());
let state = result.expect("circuit execution should succeed");
assert_eq!(state.len(), 4);
assert!(state[0].norm() > 0.0);
}
#[test]
fn test_gate_application() {
let simulator = FPGAQuantumSimulator::new(sim_config())
.expect("should create FPGA simulator for gate application test");
let mut state = Array1::zeros(4);
state[0] = Complex64::new(1.0, 0.0);
let gate = InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]);
let result = simulator.apply_single_qubit_gate_fpga(&state, &gate, 0);
assert!(result.is_ok());
let new_state = result.expect("gate application should succeed");
assert_abs_diff_eq!(new_state[0].norm(), 1.0 / 2.0_f64.sqrt(), epsilon = 1e-10);
assert_abs_diff_eq!(new_state[1].norm(), 1.0 / 2.0_f64.sqrt(), epsilon = 1e-10);
}
#[test]
fn test_rotation_gate_application_real_angle() {
let simulator =
FPGAQuantumSimulator::new(sim_config()).expect("should create FPGA simulator");
let mut state = Array1::zeros(2);
state[0] = Complex64::new(1.0, 0.0);
let gate = InterfaceGate::new(InterfaceGateType::RX(std::f64::consts::PI), vec![0]);
let new_state = simulator
.apply_single_qubit_gate_fpga(&state, &gate, 0)
.expect("rotation should apply");
assert_abs_diff_eq!(new_state[0].norm(), 0.0, epsilon = 1e-10);
assert_abs_diff_eq!(new_state[1].norm(), 1.0, epsilon = 1e-10);
}
#[test]
fn test_bitstream_management() {
let mut simulator = FPGAQuantumSimulator::new(sim_config())
.expect("should create FPGA simulator for bitstream management test");
assert!(simulator.bitstream_manager.current_config.is_some());
assert!(simulator
.bitstream_manager
.bitstreams
.contains_key("quantum_basic"));
let result = simulator.reconfigure("quantum_advanced");
assert!(result.is_ok());
assert_eq!(
simulator.bitstream_manager.current_config,
Some("quantum_advanced".to_string())
);
}
#[test]
fn test_memory_management() {
let simulator = FPGAQuantumSimulator::new(sim_config())
.expect("should create FPGA simulator for memory management test");
assert!(simulator
.memory_manager
.onchip_pools
.contains_key("state_vector"));
assert!(simulator
.memory_manager
.onchip_pools
.contains_key("gate_cache"));
assert!(!simulator.memory_manager.external_interfaces.is_empty());
}
#[test]
fn test_stats_tracking() {
let mut stats = FPGAStats::default();
stats.update_operation(10.0, 1000);
stats.update_operation(20.0, 2000);
assert_eq!(stats.total_gate_operations, 2);
assert_abs_diff_eq!(stats.total_execution_time, 30.0, epsilon = 1e-10);
assert_eq!(stats.total_clock_cycles, 3000);
}
#[test]
fn test_performance_metrics() {
let stats = FPGAStats {
total_gate_operations: 100,
total_execution_time: 1000.0,
total_clock_cycles: 300_000,
fpga_utilization: 75.0,
pipeline_efficiency: 0.85,
power_consumption: 120.0,
..Default::default()
};
let metrics = stats.get_performance_metrics();
assert!(metrics.contains_key("operations_per_second"));
assert!(metrics.contains_key("cycles_per_operation"));
assert!(metrics.contains_key("fpga_utilization"));
assert_abs_diff_eq!(metrics["operations_per_second"], 100.0, epsilon = 1e-10);
assert_abs_diff_eq!(metrics["cycles_per_operation"], 3000.0, epsilon = 1e-10);
}
#[test]
fn test_hdl_export() {
let simulator = FPGAQuantumSimulator::new(sim_config())
.expect("should create FPGA simulator for HDL export test");
let hdl_code = simulator.export_hdl("single_qubit_gate");
assert!(hdl_code.is_ok());
assert!(!hdl_code.expect("HDL export should succeed").is_empty());
assert!(simulator.export_hdl("nonexistent_module").is_err());
assert!(simulator.export_hdl("two_qubit_gate").is_err());
}
#[test]
fn test_arithmetic_precision() {
assert_eq!(ArithmeticPrecision::Fixed16, ArithmeticPrecision::Fixed16);
assert_ne!(ArithmeticPrecision::Fixed16, ArithmeticPrecision::Fixed32);
}
}