use crate::error::SparseResult;
use scirs2_core::numeric::{Float, NumAssign, NumCast, SparseElement};
use scirs2_core::random::{Rng, RngExt};
use scirs2_core::simd_ops::SimdUnifiedOps;
use std::collections::HashMap;
use std::sync::atomic::{AtomicUsize, Ordering};
#[derive(Debug, Clone, Copy)]
pub enum QuantumStrategy {
Superposition,
Entanglement,
Tunneling,
Annealing,
}
#[derive(Debug, Clone)]
pub struct QuantumSparseConfig {
pub strategy: QuantumStrategy,
pub qubit_count: usize,
pub coherence_time: f64,
pub decoherence_rate: f64,
pub temperature: f64,
pub error_correction: bool,
pub error_correction_threshold: f64,
pub logical_qubits: usize,
pub noise_model: NoiseModel,
pub coherence_model: CoherenceModel,
}
#[derive(Debug, Clone, Copy)]
pub enum NoiseModel {
Ideal,
AmplitudeDamping,
PhaseDamping,
Depolarizing,
Combined,
}
#[derive(Debug, Clone, Copy)]
pub enum CoherenceModel {
Exponential,
Gaussian,
PowerLaw,
StretchedExponential,
}
impl Default for QuantumSparseConfig {
fn default() -> Self {
Self {
strategy: QuantumStrategy::Superposition,
qubit_count: 32,
coherence_time: 1.0,
decoherence_rate: 0.01,
temperature: 1.0,
error_correction: true,
error_correction_threshold: 0.1,
logical_qubits: 16,
noise_model: NoiseModel::Combined,
coherence_model: CoherenceModel::Exponential,
}
}
}
pub struct QuantumSparseProcessor {
config: QuantumSparseConfig,
quantum_state: QuantumState,
measurement_cache: HashMap<Vec<u8>, f64>,
operation_counter: AtomicUsize,
}
#[derive(Debug, Clone)]
struct QuantumState {
amplitudes: Vec<f64>,
phases: Vec<f64>,
entanglement_matrix: Vec<Vec<f64>>,
error_syndromes: Vec<ErrorSyndrome>,
logical_qubits: Vec<LogicalQubit>,
coherence_factors: Vec<f64>,
evolution_time: f64,
}
#[derive(Debug, Clone)]
struct ErrorSyndrome {
qubit_indices: Vec<usize>,
error_type: QuantumError,
detection_probability: f64,
correction_applied: bool,
}
#[derive(Debug, Clone, Copy)]
enum QuantumError {
BitFlip,
PhaseFlip,
BitPhaseFlip,
AmplitudeDamping,
PhaseDamping,
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
struct LogicalQubit {
physical_qubits: Vec<usize>,
syndrome_qubits: Vec<usize>,
encoding_type: QuantumCode,
fidelity: f64,
}
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
enum QuantumCode {
Repetition3,
Perfect5,
Steane7,
Shor9,
Surface,
}
impl QuantumSparseProcessor {
pub fn new(config: QuantumSparseConfig) -> Self {
let qubit_count = config.qubit_count;
let state_size = 1 << qubit_count;
let logical_qubit_count = config.logical_qubits.min(qubit_count / 4); let mut logical_qubits = Vec::new();
if logical_qubit_count > 0 && qubit_count > logical_qubit_count {
for i in 0..logical_qubit_count {
let physical_start = i * 3; let syndrome_idx = if qubit_count > logical_qubit_count {
qubit_count - logical_qubit_count + i
} else {
i };
logical_qubits.push(LogicalQubit {
physical_qubits: (physical_start
..physical_start.saturating_add(3).min(qubit_count))
.collect(),
syndrome_qubits: vec![syndrome_idx.min(qubit_count.saturating_sub(1))],
encoding_type: QuantumCode::Repetition3,
fidelity: 1.0,
});
}
}
let quantum_state = QuantumState {
amplitudes: vec![1.0 / (state_size as f64).sqrt(); state_size],
phases: vec![0.0; state_size],
entanglement_matrix: vec![vec![0.0; qubit_count]; qubit_count],
error_syndromes: Vec::new(),
logical_qubits,
coherence_factors: vec![1.0; qubit_count],
evolution_time: 0.0,
};
Self {
config,
quantum_state,
measurement_cache: HashMap::new(),
operation_counter: AtomicUsize::new(0),
}
}
#[allow(clippy::too_many_arguments)]
pub fn quantum_spmv<T>(
&mut self,
rows: usize,
indptr: &[usize],
indices: &[usize],
data: &[T],
x: &[T],
y: &mut [T],
) -> SparseResult<()>
where
T: Float
+ SparseElement
+ NumAssign
+ Send
+ Sync
+ Copy
+ SimdUnifiedOps
+ Into<f64>
+ From<f64>,
{
match self.config.strategy {
QuantumStrategy::Superposition => {
self.superposition_spmv(rows, indptr, indices, data, x, y)
}
QuantumStrategy::Entanglement => {
self.entanglement_spmv(rows, indptr, indices, data, x, y)
}
QuantumStrategy::Tunneling => self.tunneling_spmv(rows, indptr, indices, data, x, y),
QuantumStrategy::Annealing => self.annealing_spmv(rows, indptr, indices, data, x, y),
}
}
fn superposition_spmv<T>(
&mut self,
rows: usize,
indptr: &[usize],
indices: &[usize],
data: &[T],
x: &[T],
y: &mut [T],
) -> SparseResult<()>
where
T: Float
+ SparseElement
+ NumAssign
+ Send
+ Sync
+ Copy
+ SimdUnifiedOps
+ Into<f64>
+ From<f64>,
{
let qubit_count = (rows as f64).log2().ceil() as usize;
self.prepare_superposition_state(rows);
let register_size = 1 << qubit_count.min(self.config.qubit_count);
let chunk_size = rows.div_ceil(register_size);
for chunk_start in (0..rows).step_by(chunk_size) {
let chunk_end = (chunk_start + chunk_size).min(rows);
for row in chunk_start..chunk_end {
let start_idx = indptr[row];
let end_idx = indptr[row + 1];
if end_idx > start_idx {
let mut quantum_sum = 0.0;
let amplitude =
self.quantum_state.amplitudes[row % self.quantum_state.amplitudes.len()];
for idx in start_idx..end_idx {
let col = indices[idx];
let data_val: f64 = data[idx].into();
let x_val: f64 = x[col].into();
quantum_sum += amplitude * data_val * x_val;
}
y[row] = NumCast::from(quantum_sum).unwrap_or(T::sparse_zero());
}
}
self.apply_decoherence();
}
self.operation_counter.fetch_add(1, Ordering::Relaxed);
Ok(())
}
fn entanglement_spmv<T>(
&mut self,
rows: usize,
indptr: &[usize],
indices: &[usize],
data: &[T],
x: &[T],
y: &mut [T],
) -> SparseResult<()>
where
T: Float
+ SparseElement
+ NumAssign
+ Send
+ Sync
+ Copy
+ SimdUnifiedOps
+ Into<f64>
+ From<f64>,
{
self.build_entanglement_matrix(rows, indptr, indices);
let mut processed = vec![false; rows];
for row in 0..rows {
if processed[row] {
continue;
}
let entangled_rows = self.find_entangled_rows(row, rows, indptr, indices);
for &entangled_row in &entangled_rows {
if !processed[entangled_row] {
let start_idx = indptr[entangled_row];
let end_idx = indptr[entangled_row + 1];
let mut sum = 0.0;
for idx in start_idx..end_idx {
let col = indices[idx];
let data_val: f64 = data[idx].into();
let x_val: f64 = x[col].into();
let correlation = self.quantum_state.entanglement_matrix
[row % self.config.qubit_count]
[entangled_row % self.config.qubit_count];
sum += (1.0 + correlation) * data_val * x_val;
}
y[entangled_row] = NumCast::from(sum).unwrap_or(T::sparse_zero());
processed[entangled_row] = true;
}
}
}
Ok(())
}
fn tunneling_spmv<T>(
&mut self,
rows: usize,
indptr: &[usize],
indices: &[usize],
data: &[T],
x: &[T],
y: &mut [T],
) -> SparseResult<()>
where
T: Float
+ SparseElement
+ NumAssign
+ Send
+ Sync
+ Copy
+ SimdUnifiedOps
+ Into<f64>
+ From<f64>,
{
let barriers = self.identify_computational_barriers(rows, indptr);
for row in 0..rows {
let start_idx = indptr[row];
let end_idx = indptr[row + 1];
if barriers.contains(&row) {
let tunnel_probability = self.calculate_tunnel_probability(row, &barriers);
if tunnel_probability > 0.5 {
y[row] = self.interpolate_result(row, rows, y);
} else {
let mut sum = 0.0;
for idx in start_idx..end_idx {
let col = indices[idx];
let data_val: f64 = data[idx].into();
let x_val: f64 = x[col].into();
sum += data_val * x_val;
}
y[row] = NumCast::from(sum).unwrap_or(T::sparse_zero());
}
} else {
let mut sum = 0.0;
for idx in start_idx..end_idx {
let col = indices[idx];
let data_val: f64 = data[idx].into();
let x_val: f64 = x[col].into();
sum += data_val * x_val;
}
y[row] = NumCast::from(sum).unwrap_or(T::sparse_zero());
}
}
Ok(())
}
fn annealing_spmv<T>(
&mut self,
rows: usize,
indptr: &[usize],
indices: &[usize],
data: &[T],
x: &[T],
y: &mut [T],
) -> SparseResult<()>
where
T: Float
+ SparseElement
+ NumAssign
+ Send
+ Sync
+ Copy
+ SimdUnifiedOps
+ Into<f64>
+ From<f64>,
{
let mut processing_order = (0..rows).collect::<Vec<_>>();
let mut current_temperature = self.config.temperature;
let annealing_steps = 100;
let cooling_rate = 0.95;
for step in 0..annealing_steps {
let current_energy = self.calculate_processing_energy(&processing_order, indptr);
let mut new_order = processing_order.clone();
if rows > 1 {
let i = step % rows;
let j = (step + 1) % rows;
new_order.swap(i, j);
}
let new_energy = self.calculate_processing_energy(&new_order, indptr);
let delta_energy = new_energy - current_energy;
let acceptance_probability = if delta_energy < 0.0 {
1.0
} else {
(-delta_energy / current_temperature).exp()
};
if scirs2_core::random::rng().random::<f64>() < acceptance_probability {
processing_order = new_order;
}
current_temperature *= cooling_rate;
}
for &row in &processing_order {
let start_idx = indptr[row];
let end_idx = indptr[row + 1];
let mut sum = 0.0;
for idx in start_idx..end_idx {
let col = indices[idx];
let data_val: f64 = data[idx].into();
let x_val: f64 = x[col].into();
sum += data_val * x_val;
}
y[row] = NumCast::from(sum).unwrap_or(T::sparse_zero());
}
Ok(())
}
fn prepare_superposition_state(&mut self, rows: usize) {
let state_size = self.quantum_state.amplitudes.len();
let normalization = 1.0 / (rows as f64).sqrt();
for i in 0..state_size.min(rows) {
self.quantum_state.amplitudes[i] = normalization;
self.quantum_state.phases[i] = 0.0;
}
}
fn apply_decoherence(&mut self) {
self.quantum_state.evolution_time += 0.001;
match self.config.coherence_model {
CoherenceModel::Exponential => {
let decoherence_factor =
(-self.config.decoherence_rate * self.quantum_state.evolution_time).exp();
let coherence_len = self.quantum_state.coherence_factors.len();
for (i, amplitude) in self.quantum_state.amplitudes.iter_mut().enumerate() {
*amplitude *= decoherence_factor;
self.quantum_state.coherence_factors[i % coherence_len] = decoherence_factor;
}
}
CoherenceModel::Gaussian => {
let variance = self.config.decoherence_rate * self.quantum_state.evolution_time;
let decoherence_factor = (-variance.powi(2) / 2.0).exp();
for amplitude in &mut self.quantum_state.amplitudes {
*amplitude *= decoherence_factor;
}
}
CoherenceModel::PowerLaw => {
let alpha = 2.0; let decoherence_factor = (1.0
+ self.config.decoherence_rate * self.quantum_state.evolution_time.powf(alpha))
.recip();
for amplitude in &mut self.quantum_state.amplitudes {
*amplitude *= decoherence_factor;
}
}
CoherenceModel::StretchedExponential => {
let beta = 0.5; let decoherence_factor = (-(self.config.decoherence_rate
* self.quantum_state.evolution_time)
.powf(beta))
.exp();
for amplitude in &mut self.quantum_state.amplitudes {
*amplitude *= decoherence_factor;
}
}
}
self.apply_noise_model();
if self.config.error_correction {
self.perform_error_correction();
}
}
fn build_entanglement_matrix(&mut self, rows: usize, indptr: &[usize], indices: &[usize]) {
let n = self.config.qubit_count;
for i in 0..n {
for j in 0..n {
self.quantum_state.entanglement_matrix[i][j] = 0.0;
}
}
for row1 in 0..rows.min(n) {
for row2 in (row1 + 1)..rows.min(n) {
let start1 = indptr[row1];
let end1 = indptr[row1 + 1];
let start2 = indptr[row2];
let end2 = indptr[row2 + 1];
let shared_cols =
self.count_shared_columns(&indices[start1..end1], &indices[start2..end2]);
let entanglement =
shared_cols as f64 / ((end1 - start1).max(end2 - start2) as f64 + 1.0);
self.quantum_state.entanglement_matrix[row1][row2] = entanglement;
self.quantum_state.entanglement_matrix[row2][row1] = entanglement;
}
}
}
fn find_entangled_rows(
&self,
row: usize,
rows: usize,
indptr: &[usize],
indices: &[usize],
) -> Vec<usize> {
let mut entangled = vec![row];
let start = indptr[row];
let end = indptr[row + 1];
let row_cols = &indices[start..end];
for other_row in 0..rows {
if other_row == row {
continue;
}
let other_start = indptr[other_row];
let other_end = indptr[other_row + 1];
let other_cols = &indices[other_start..other_end];
let shared = self.count_shared_columns(row_cols, other_cols);
let entanglement_threshold = (row_cols.len().min(other_cols.len()) / 4).max(1);
if shared >= entanglement_threshold {
entangled.push(other_row);
}
}
entangled
}
fn count_shared_columns(&self, cols1: &[usize], cols2: &[usize]) -> usize {
let mut shared = 0;
let mut i = 0;
let mut j = 0;
while i < cols1.len() && j < cols2.len() {
match cols1[i].cmp(&cols2[j]) {
std::cmp::Ordering::Equal => {
shared += 1;
i += 1;
j += 1;
}
std::cmp::Ordering::Less => {
i += 1;
}
std::cmp::Ordering::Greater => {
j += 1;
}
}
}
shared
}
fn identify_computational_barriers(&self, rows: usize, indptr: &[usize]) -> Vec<usize> {
let mut barriers = Vec::new();
let avg_nnz = indptr
.get(rows)
.copied()
.unwrap_or(0)
.checked_div(rows)
.unwrap_or(0);
for row in 0..rows {
let nnz = indptr[row + 1] - indptr[row];
if nnz > avg_nnz * 3 {
barriers.push(row);
}
}
barriers
}
fn calculate_tunnel_probability(&self, row: usize, barriers: &[usize]) -> f64 {
let _position = barriers.iter().position(|&b| b == row).unwrap_or(0) as f64;
let barrier_height = barriers.len() as f64;
let transmission = (-2.0 * barrier_height.sqrt()).exp();
transmission.clamp(0.0, 1.0)
}
fn interpolate_result<T>(&self, row: usize, rows: usize, y: &[T]) -> T
where
T: Float + SparseElement + NumAssign + Send + Sync + Copy + Into<f64> + From<f64>,
{
let prev_row = if row > 0 { row - 1 } else { 0 };
let next_row = if row < rows - 1 { row + 1 } else { rows - 1 };
if prev_row == next_row {
return T::sparse_zero();
}
let prev_val: f64 = y[prev_row].into();
let next_val: f64 = y[next_row].into();
let interpolated = (prev_val + next_val) / 2.0;
NumCast::from(interpolated).unwrap_or(T::sparse_zero())
}
fn calculate_processing_energy(&self, order: &[usize], indptr: &[usize]) -> f64 {
let mut energy = 0.0;
let mut _cache_hits = 0;
let cache_size = 64; let mut cache = std::collections::VecDeque::new();
for &row in order {
let nnz = indptr[row + 1] - indptr[row];
energy += nnz as f64;
if cache.contains(&row) {
_cache_hits += 1;
energy -= 0.5; } else {
if cache.len() >= cache_size {
cache.pop_front();
}
cache.push_back(row);
energy += 1.0; }
}
energy
}
fn apply_noise_model(&mut self) {
match self.config.noise_model {
NoiseModel::Ideal => {} NoiseModel::AmplitudeDamping => {
let gamma = self.config.decoherence_rate * 0.1;
for amplitude in &mut self.quantum_state.amplitudes {
*amplitude *= (1.0 - gamma).sqrt();
}
}
NoiseModel::PhaseDamping => {
let gamma = self.config.decoherence_rate * 0.1;
for (i, phase) in self.quantum_state.phases.iter_mut().enumerate() {
let random_phase = (scirs2_core::random::rng().random::<f64>() - 0.5) * gamma;
*phase += random_phase;
if i < self.quantum_state.amplitudes.len() {
self.quantum_state.amplitudes[i] *= 1.0 - gamma / 2.0;
}
}
}
NoiseModel::Depolarizing => {
let p = self.config.decoherence_rate * 0.05;
for amplitude in &mut self.quantum_state.amplitudes {
if scirs2_core::random::rng().random::<f64>() < p {
*amplitude *= 0.5; }
}
}
NoiseModel::Combined => {
let gamma_amp = self.config.decoherence_rate * 0.05;
let gamma_phase = self.config.decoherence_rate * 0.1;
for (i, amplitude) in self.quantum_state.amplitudes.iter_mut().enumerate() {
*amplitude *= (1.0 - gamma_amp).sqrt();
if i < self.quantum_state.phases.len() {
let random_phase =
(scirs2_core::random::rng().random::<f64>() - 0.5) * gamma_phase;
self.quantum_state.phases[i] += random_phase;
}
}
}
}
}
fn perform_error_correction(&mut self) {
self.detect_error_syndromes();
let syndromes_to_correct: Vec<_> = self
.quantum_state
.error_syndromes
.iter()
.enumerate()
.filter(|(_, syndrome)| {
!syndrome.correction_applied
&& syndrome.detection_probability > self.config.error_correction_threshold
})
.map(|(i, syndrome)| (i, syndrome.clone()))
.collect();
for (index, syndrome) in syndromes_to_correct {
self.apply_error_correction(&syndrome);
self.quantum_state.error_syndromes[index].correction_applied = true;
}
self.update_logical_qubit_fidelities();
self.quantum_state
.error_syndromes
.retain(|s| !s.correction_applied || s.detection_probability > 0.9);
}
fn detect_error_syndromes(&mut self) {
for logical_qubit in &self.quantum_state.logical_qubits {
let syndrome_strength = self.measure_syndrome_strength(logical_qubit);
if syndrome_strength > self.config.error_correction_threshold {
let error_type = self.classify_error_type(logical_qubit, syndrome_strength);
let syndrome = ErrorSyndrome {
qubit_indices: logical_qubit.physical_qubits.clone(),
error_type,
detection_probability: syndrome_strength,
correction_applied: false,
};
self.quantum_state.error_syndromes.push(syndrome);
}
}
}
fn measure_syndrome_strength(&self, logicalqubit: &LogicalQubit) -> f64 {
let mut syndrome_strength = 0.0;
for &physical_qubit in &logicalqubit.physical_qubits {
if physical_qubit < self.quantum_state.coherence_factors.len() {
let coherence = self.quantum_state.coherence_factors[physical_qubit];
syndrome_strength += (1.0 - coherence).abs();
}
}
syndrome_strength / logicalqubit.physical_qubits.len() as f64
}
fn classify_error_type(
&self,
_logical_qubit: &LogicalQubit,
syndrome_strength: f64,
) -> QuantumError {
if syndrome_strength > 0.8 {
QuantumError::BitPhaseFlip
} else if syndrome_strength > 0.5 {
if scirs2_core::random::rng().random::<f64>() > 0.5 {
QuantumError::BitFlip
} else {
QuantumError::PhaseFlip
}
} else if syndrome_strength > 0.3 {
QuantumError::AmplitudeDamping
} else {
QuantumError::PhaseDamping
}
}
fn apply_error_correction(&mut self, syndrome: &ErrorSyndrome) {
match syndrome.error_type {
QuantumError::BitFlip => {
for &qubit_idx in &syndrome.qubit_indices {
if qubit_idx < self.quantum_state.amplitudes.len() {
self.quantum_state.amplitudes[qubit_idx] =
-self.quantum_state.amplitudes[qubit_idx];
}
}
}
QuantumError::PhaseFlip => {
for &qubit_idx in &syndrome.qubit_indices {
if qubit_idx < self.quantum_state.phases.len() {
self.quantum_state.phases[qubit_idx] += std::f64::consts::PI;
}
}
}
QuantumError::BitPhaseFlip => {
for &qubit_idx in &syndrome.qubit_indices {
if qubit_idx < self.quantum_state.amplitudes.len() {
self.quantum_state.amplitudes[qubit_idx] =
-self.quantum_state.amplitudes[qubit_idx];
}
if qubit_idx < self.quantum_state.phases.len() {
self.quantum_state.phases[qubit_idx] += std::f64::consts::PI;
}
}
}
QuantumError::AmplitudeDamping => {
for &qubit_idx in &syndrome.qubit_indices {
if qubit_idx < self.quantum_state.coherence_factors.len() {
self.quantum_state.coherence_factors[qubit_idx] =
(self.quantum_state.coherence_factors[qubit_idx] + 1.0) / 2.0;
}
}
}
QuantumError::PhaseDamping => {
for &qubit_idx in &syndrome.qubit_indices {
if qubit_idx < self.quantum_state.phases.len() {
self.quantum_state.phases[qubit_idx] *= 0.9; }
}
}
}
}
fn update_logical_qubit_fidelities(&mut self) {
for logical_qubit in &mut self.quantum_state.logical_qubits {
let mut total_coherence = 0.0;
let mut count = 0;
for &physical_qubit in &logical_qubit.physical_qubits {
if physical_qubit < self.quantum_state.coherence_factors.len() {
total_coherence += self.quantum_state.coherence_factors[physical_qubit];
count += 1;
}
}
if count > 0 {
logical_qubit.fidelity = total_coherence / count as f64;
}
}
}
pub fn get_stats(&self) -> QuantumProcessorStats {
let avg_logical_fidelity = if !self.quantum_state.logical_qubits.is_empty() {
self.quantum_state
.logical_qubits
.iter()
.map(|q| q.fidelity)
.sum::<f64>()
/ self.quantum_state.logical_qubits.len() as f64
} else {
0.0
};
QuantumProcessorStats {
operations_count: self.operation_counter.load(Ordering::Relaxed),
coherence_time: self.config.coherence_time,
decoherence_rate: self.config.decoherence_rate,
entanglement_strength: self.calculate_average_entanglement(),
cache_efficiency: self.measurement_cache.len() as f64,
error_correction_enabled: self.config.error_correction,
active_error_syndromes: self.quantum_state.error_syndromes.len(),
average_logical_fidelity: avg_logical_fidelity,
evolution_time: self.quantum_state.evolution_time,
}
}
fn calculate_average_entanglement(&self) -> f64 {
let n = self.config.qubit_count;
let mut total = 0.0;
let mut count = 0;
for i in 0..n {
for j in (i + 1)..n {
total += self.quantum_state.entanglement_matrix[i][j].abs();
count += 1;
}
}
if count > 0 {
total / count as f64
} else {
0.0
}
}
}
#[derive(Debug)]
pub struct QuantumProcessorStats {
pub operations_count: usize,
pub coherence_time: f64,
pub decoherence_rate: f64,
pub entanglement_strength: f64,
pub cache_efficiency: f64,
pub error_correction_enabled: bool,
pub active_error_syndromes: usize,
pub average_logical_fidelity: f64,
pub evolution_time: f64,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_quantum_sparse_processor_creation() {
let config = QuantumSparseConfig {
qubit_count: 8, ..Default::default()
};
let processor = QuantumSparseProcessor::new(config);
assert_eq!(processor.config.qubit_count, 8);
assert_eq!(
processor.config.strategy as u8,
QuantumStrategy::Superposition as u8
);
}
#[test]
fn test_superposition_spmv() {
let config = QuantumSparseConfig {
strategy: QuantumStrategy::Superposition,
qubit_count: 4,
..Default::default()
};
let mut processor = QuantumSparseProcessor::new(config);
let indptr = vec![0, 2, 3];
let indices = vec![0, 1, 1];
let data = vec![1.0, 2.0, 3.0];
let x = vec![1.0, 1.0];
let mut y = vec![0.0; 2];
processor
.quantum_spmv(2, &indptr, &indices, &data, &x, &mut y)
.expect("Operation failed");
assert!(y[0] > 2.0 && y[0] < 4.0);
assert!(y[1] > 2.0 && y[1] < 4.0);
}
#[test]
fn test_quantum_processor_stats() {
let config = QuantumSparseConfig {
qubit_count: 8, ..Default::default()
};
let processor = QuantumSparseProcessor::new(config);
let stats = processor.get_stats();
assert_eq!(stats.operations_count, 0);
assert_eq!(stats.coherence_time, 1.0);
assert_eq!(stats.decoherence_rate, 0.01);
}
}