use crate::qis::{DensityMatrix, Statevector};
use crate::visualization::VisualizationError;
use num_complex::Complex64;
pub trait StateVisualizationSource {
fn num_qubits(&self) -> usize;
fn density_matrix_data(&self) -> Result<Vec<Complex64>, VisualizationError>;
}
impl StateVisualizationSource for Statevector {
fn num_qubits(&self) -> usize {
self.num_qubits
}
fn density_matrix_data(&self) -> Result<Vec<Complex64>, VisualizationError> {
let num_qubits = self.num_qubits;
let data = self.data();
let dim = checked_dim(num_qubits)?;
let density_len = checked_density_len(num_qubits)?;
if data.len() != dim {
return Err(VisualizationError::InvalidInput(format!(
"statevector length {} does not match 2^{num_qubits}",
data.len()
)));
}
let mut rho = vec![Complex64::new(0.0, 0.0); density_len];
for row in 0..dim {
for col in 0..dim {
rho[row * dim + col] = data[row] * data[col].conj();
}
}
Ok(rho)
}
}
impl StateVisualizationSource for DensityMatrix {
fn num_qubits(&self) -> usize {
self.num_qubits
}
fn density_matrix_data(&self) -> Result<Vec<Complex64>, VisualizationError> {
let num_qubits = self.num_qubits;
let density_len = checked_density_len(num_qubits)?;
let data = self.data();
if data.len() != density_len {
return Err(VisualizationError::InvalidInput(format!(
"density matrix length {} does not match 4^{num_qubits}",
data.len()
)));
}
Ok(data.to_vec())
}
}
pub fn state_to_density_matrix<S: StateVisualizationSource + ?Sized>(
state: &S,
) -> Result<(usize, Vec<Complex64>), VisualizationError> {
let num_qubits = state.num_qubits();
let rho = state.density_matrix_data()?;
let density_len = checked_density_len(num_qubits)?;
if rho.len() != density_len {
return Err(VisualizationError::InvalidInput(format!(
"density matrix length {} does not match 4^{num_qubits}",
rho.len()
)));
}
Ok((num_qubits, rho))
}
pub(crate) fn checked_dim(num_qubits: usize) -> Result<usize, VisualizationError> {
if num_qubits >= usize::BITS as usize {
return Err(VisualizationError::InvalidInput(
"too many qubits for state visualization".to_string(),
));
}
Ok(1usize << num_qubits)
}
pub(crate) fn checked_density_len(num_qubits: usize) -> Result<usize, VisualizationError> {
let dim = checked_dim(num_qubits)?;
dim.checked_mul(dim).ok_or_else(|| {
VisualizationError::InvalidInput("too many qubits for state visualization".to_string())
})
}
pub(crate) fn basis_labels(num_qubits: usize, reverse_bits: bool) -> Vec<String> {
let dim = 1usize << num_qubits;
(0..dim)
.map(|value| {
let raw = format!("{value:0num_qubits$b}");
if reverse_bits {
raw.chars().rev().collect()
} else {
raw
}
})
.collect()
}