use crate::CalculatorFloat;
#[cfg(feature = "json_schema")]
use crate::Complex64Def;
use crate::RoqoqoError;
use num_complex::Complex64;
use std::collections::HashMap;
pub type SingleReadoutPauliProductMasks = HashMap<usize, PauliProductMask>;
pub type PauliProductMask = Vec<usize>;
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "json_schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub enum PauliProductsToExpVal {
Linear(HashMap<usize, f64>),
Symbolic(CalculatorFloat),
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "json_schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub struct PauliZProductInput {
pub pauli_product_qubit_masks: HashMap<String, SingleReadoutPauliProductMasks>,
pub number_qubits: usize,
pub number_pauli_products: usize,
pub measured_exp_vals: HashMap<String, PauliProductsToExpVal>,
pub use_flipped_measurement: bool,
}
impl PauliZProductInput {
pub fn new(number_qubits: usize, use_flipped_measurement: bool) -> Self {
Self {
pauli_product_qubit_masks: HashMap::new(),
number_qubits,
number_pauli_products: 0,
measured_exp_vals: HashMap::new(),
use_flipped_measurement,
}
}
pub fn add_pauliz_product(
&mut self,
readout: String,
pauli_product_mask: PauliProductMask,
) -> Result<usize, RoqoqoError> {
if let Some(i) = &pauli_product_mask
.iter()
.find(|i| i >= &&self.number_qubits)
{
return Err(RoqoqoError::PauliProductExceedsQubits {
pp_qubit: **i,
number_qubits: self.number_qubits,
});
}
if let Some(m) = self.pauli_product_qubit_masks.get_mut(&readout) {
if let Some((k, _)) = m.iter().find(|(_, v)| v == &&pauli_product_mask) {
return Ok(*k);
}
m.insert(self.number_pauli_products, pauli_product_mask);
} else {
let mut new_map = HashMap::new();
new_map.insert(self.number_pauli_products, pauli_product_mask);
self.pauli_product_qubit_masks.insert(readout, new_map);
}
self.number_pauli_products += 1;
Ok(self.number_pauli_products - 1)
}
pub fn add_linear_exp_val(
&mut self,
name: String,
linear: HashMap<usize, f64>,
) -> Result<(), RoqoqoError> {
if self
.measured_exp_vals
.insert(name.clone(), PauliProductsToExpVal::Linear(linear))
.is_some()
{
return Err(RoqoqoError::ExpValUsedTwice { name });
}
Ok(())
}
pub fn add_symbolic_exp_val(
&mut self,
name: String,
symbolic: CalculatorFloat,
) -> Result<(), RoqoqoError> {
if self
.measured_exp_vals
.insert(name.clone(), PauliProductsToExpVal::Symbolic(symbolic))
.is_some()
{
return Err(RoqoqoError::ExpValUsedTwice { name });
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "json_schema", derive(schemars::JsonSchema))]
pub struct CheatedPauliZProductInput {
pub measured_exp_vals: HashMap<String, PauliProductsToExpVal>,
pub pauli_product_keys: HashMap<String, usize>,
}
impl Default for CheatedPauliZProductInput {
fn default() -> Self {
Self::new()
}
}
impl CheatedPauliZProductInput {
pub fn new() -> Self {
Self {
measured_exp_vals: HashMap::new(),
pauli_product_keys: HashMap::new(),
}
}
pub fn add_pauliz_product(&mut self, readout: String) -> usize {
if let Some((_, v)) = self.pauli_product_keys.iter().find(|(k, _)| k == &&readout) {
return *v;
}
self.pauli_product_keys
.insert(readout, self.pauli_product_keys.len());
self.pauli_product_keys.len() - 1
}
pub fn add_linear_exp_val(
&mut self,
name: String,
linear: HashMap<usize, f64>,
) -> Result<(), RoqoqoError> {
if self
.measured_exp_vals
.insert(name.clone(), PauliProductsToExpVal::Linear(linear))
.is_some()
{
return Err(RoqoqoError::ExpValUsedTwice { name });
}
Ok(())
}
pub fn add_symbolic_exp_val(
&mut self,
name: String,
symbolic: CalculatorFloat,
) -> Result<(), RoqoqoError> {
if self
.measured_exp_vals
.insert(name.clone(), PauliProductsToExpVal::Symbolic(symbolic))
.is_some()
{
return Err(RoqoqoError::ExpValUsedTwice { name });
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub struct CheatedInput {
pub measured_operators: HashMap<String, (OperatorSparseVec, String)>,
pub number_qubits: usize,
}
#[cfg(feature = "json_schema")]
impl schemars::JsonSchema for CheatedInput {
fn schema_name() -> std::borrow::Cow<'static, str> {
"CheatedInput".into()
}
fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
<SchemaHelperCheatedInput>::json_schema(generator)
}
}
#[cfg(feature = "json_schema")]
#[derive(schemars::JsonSchema)]
#[allow(dead_code, clippy::type_complexity)]
struct SchemaHelperCheatedInput {
measured_operators: HashMap<String, (Vec<(usize, usize, Complex64Def)>, String)>,
number_qubits: usize,
}
pub type OperatorSparseVec = Vec<(usize, usize, Complex64)>;
impl CheatedInput {
pub fn new(number_qubits: usize) -> Self {
Self {
measured_operators: HashMap::new(),
number_qubits,
}
}
pub fn add_operator_exp_val(
&mut self,
name: String,
operator: OperatorSparseVec,
readout: String,
) -> Result<(), RoqoqoError> {
let dimension = 2_usize.pow(self.number_qubits as u32);
if let Some((x, y, _)) = operator
.iter()
.find(|(x, y, _)| x >= &dimension || y >= &dimension)
{
return Err(RoqoqoError::MismatchedOperatorDimension {
index: (*x, *y),
number_qubits: self.number_qubits,
});
}
if self
.measured_operators
.insert(name.clone(), (operator, readout))
.is_some()
{
return Err(RoqoqoError::ExpValUsedTwice { name });
}
Ok(())
}
}
impl crate::operations::SupportedVersion for CheatedInput {}
impl crate::operations::SupportedVersion for CheatedPauliZProductInput {}
impl crate::operations::SupportedVersion for PauliZProductInput {}