#[cfg(feature = "unstable_parallel_run")]
use rayon::prelude::*;
use std::collections::HashMap;
#[cfg(feature = "async")]
use crate::backends::AsyncEvaluatingBackend;
use crate::backends::{EvaluatingBackend, RegisterResult};
use crate::measurements;
use crate::measurements::Measure;
use crate::RoqoqoBackendError;
use std::fmt::{Display, Formatter};
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "json_schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub enum QuantumProgram {
PauliZProduct {
measurement: measurements::PauliZProduct,
input_parameter_names: Vec<String>,
},
CheatedPauliZProduct {
measurement: measurements::CheatedPauliZProduct,
input_parameter_names: Vec<String>,
},
Cheated {
measurement: measurements::Cheated,
input_parameter_names: Vec<String>,
},
ClassicalRegister {
measurement: measurements::ClassicalRegister,
input_parameter_names: Vec<String>,
},
}
impl QuantumProgram {
pub fn run<T>(
&self,
backend: T,
parameters: &[f64],
) -> Result<Option<HashMap<String, f64>>, RoqoqoBackendError>
where
T: EvaluatingBackend,
{
match self{
QuantumProgram::PauliZProduct{measurement, input_parameter_names } => {
if parameters.len() != input_parameter_names.len() { return Err(RoqoqoBackendError::GenericError{msg: format!("Wrong number of parameters {} parameters expected {} parameters given", input_parameter_names.len(), parameters.len())})};
let substituted_parameters: HashMap<String, f64> = input_parameter_names.iter().zip(parameters.iter()).map(|(key, value)| (key.clone(), *value)).collect();
let substituted_measurement = measurement.substitute_parameters(
substituted_parameters
)?;
backend.run_measurement(&substituted_measurement)
}
QuantumProgram::CheatedPauliZProduct{measurement, input_parameter_names } => {
if parameters.len() != input_parameter_names.len() { return Err(RoqoqoBackendError::GenericError{msg: format!("Wrong number of parameters {} parameters expected {} parameters given", input_parameter_names.len(), parameters.len())})};
let substituted_parameters: HashMap<String, f64> = input_parameter_names.iter().zip(parameters.iter()).map(|(key, value)| (key.clone(), *value)).collect();
let substituted_measurement = measurement.substitute_parameters(
substituted_parameters
)?;
backend.run_measurement(&substituted_measurement)
}
QuantumProgram::Cheated{measurement, input_parameter_names } => {
if parameters.len() != input_parameter_names.len() { return Err(RoqoqoBackendError::GenericError{msg: format!("Wrong number of parameters {} parameters expected {} parameters given", input_parameter_names.len(), parameters.len())})};
let substituted_parameters: HashMap<String, f64> = input_parameter_names.iter().zip(parameters.iter()).map(|(key, value)| (key.clone(), *value)).collect();
let substituted_measurement = measurement.substitute_parameters(
substituted_parameters
)?;
backend.run_measurement(&substituted_measurement)
}
_ => Err(RoqoqoBackendError::GenericError{msg: "A quantum programm returning classical registeres cannot be executed by `run` use `run_registers` instead".to_string()})
}
}
#[cfg(feature = "unstable_parallel_run")]
pub fn run_parallel<T>(
&self,
backend: T,
vec_parameters: &[Vec<f64>],
) -> Result<Vec<Option<HashMap<String, f64>>>, RoqoqoBackendError>
where
T: EvaluatingBackend + Sync,
{
match self{
QuantumProgram::PauliZProduct{measurement, input_parameter_names } => {
if vec_parameters[0].len() != input_parameter_names.len() {
return Err(RoqoqoBackendError::GenericError {
msg: format!(
"Wrong number of parameters {} parameters expected {} parameters given",
input_parameter_names.len(),
vec_parameters[0].len()
),
});
};
vec_parameters
.into_par_iter()
.map(|parameters| {
let substituted_parameters: HashMap<String, f64> = input_parameter_names
.iter()
.zip(parameters.iter())
.map(|(key, value)| (key.clone(), *value))
.collect();
let m = measurement
.substitute_parameters(substituted_parameters)
.expect("Failed to substitute parameters in measurement");
backend.run_measurement(&m)
})
.collect()
}
QuantumProgram::CheatedPauliZProduct{measurement, input_parameter_names } => {
if vec_parameters[0].len() != input_parameter_names.len() {
return Err(RoqoqoBackendError::GenericError {
msg: format!(
"Wrong number of parameters {} parameters expected {} parameters given",
input_parameter_names.len(),
vec_parameters[0].len()
),
});
};
vec_parameters
.into_par_iter()
.map(|parameters| {
let substituted_parameters: HashMap<String, f64> = input_parameter_names
.iter()
.zip(parameters.iter())
.map(|(key, value)| (key.clone(), *value))
.collect();
let m = measurement
.substitute_parameters(substituted_parameters)
.expect("Failed to substitute parameters in measurement");
backend.run_measurement(&m)
})
.collect()
}
QuantumProgram::Cheated{measurement, input_parameter_names } => {
if vec_parameters[0].len() != input_parameter_names.len() {
return Err(RoqoqoBackendError::GenericError {
msg: format!(
"Wrong number of parameters {} parameters expected {} parameters given",
input_parameter_names.len(),
vec_parameters[0].len()
),
});
};
vec_parameters
.into_par_iter()
.map(|parameters| {
let substituted_parameters: HashMap<String, f64> = input_parameter_names
.iter()
.zip(parameters.iter())
.map(|(key, value)| (key.clone(), *value))
.collect();
let m = measurement
.substitute_parameters(substituted_parameters)
.expect("Failed to substitute parameters in measurement");
backend.run_measurement(&m)
})
.collect()
}
_ => Err(RoqoqoBackendError::GenericError{msg: "A quantum programm returning classical registeres cannot be executed by `run` use `run_registers` instead".to_string()})
}
}
pub fn run_registers<T>(&self, backend: T, parameters: &[f64]) -> RegisterResult
where
T: EvaluatingBackend,
{
match self{
QuantumProgram::ClassicalRegister{measurement, input_parameter_names } => {
if parameters.len() != input_parameter_names.len() { return Err(RoqoqoBackendError::GenericError{msg: format!("Wrong number of parameters {} parameters expected {} parameters given", input_parameter_names.len(), parameters.len())})};
let substituted_parameters: HashMap<String, f64> = input_parameter_names.iter().zip(parameters.iter()).map(|(key, value)| (key.clone(), *value)).collect();
let substituted_measurement = measurement.substitute_parameters(
substituted_parameters
)?;
backend.run_measurement_registers(&substituted_measurement)
}
_ => Err(RoqoqoBackendError::GenericError{msg: "A quantum programm returning expectation values cannot be executed by `run_registers` use `run` instead".to_string()})
}
}
#[cfg(feature = "async")]
pub async fn async_run<T>(
&self,
backend: T,
parameters: &[f64],
) -> Result<Option<HashMap<String, f64>>, RoqoqoBackendError>
where
T: AsyncEvaluatingBackend,
T: Sync,
{
match self{
QuantumProgram::PauliZProduct{measurement, input_parameter_names } => {
if parameters.len() != input_parameter_names.len() { return Err(RoqoqoBackendError::GenericError{msg: format!("Wrong number of parameters {} parameters expected {} parameters given", input_parameter_names.len(), parameters.len())})};
let substituted_parameters: HashMap<String, f64> = input_parameter_names.iter().zip(parameters.iter()).map(|(key, value)| (key.clone(), *value)).collect();
let substituted_measurement = measurement.substitute_parameters(
substituted_parameters
)?;
backend.async_run_measurement(&substituted_measurement).await
}
QuantumProgram::CheatedPauliZProduct{measurement, input_parameter_names } => {
if parameters.len() != input_parameter_names.len() { return Err(RoqoqoBackendError::GenericError{msg: format!("Wrong number of parameters {} parameters expected {} parameters given", input_parameter_names.len(), parameters.len())})};
let substituted_parameters: HashMap<String, f64> = input_parameter_names.iter().zip(parameters.iter()).map(|(key, value)| (key.clone(), *value)).collect();
let substituted_measurement = measurement.substitute_parameters(
substituted_parameters
)?;
backend.async_run_measurement(&substituted_measurement).await
}
QuantumProgram::Cheated{measurement, input_parameter_names } => {
if parameters.len() != input_parameter_names.len() { return Err(RoqoqoBackendError::GenericError{msg: format!("Wrong number of parameters {} parameters expected {} parameters given", input_parameter_names.len(), parameters.len())})};
let substituted_parameters: HashMap<String, f64> = input_parameter_names.iter().zip(parameters.iter()).map(|(key, value)| (key.clone(), *value)).collect();
let substituted_measurement = measurement.substitute_parameters(
substituted_parameters
)?;
backend.async_run_measurement(&substituted_measurement).await
}
_ => Err(RoqoqoBackendError::GenericError{msg: "A quantum programm returning classical registeres cannot be executed by `run` use `run_registers` instead".to_string()})
}
}
#[cfg(feature = "async")]
pub async fn async_run_registers<T>(&self, backend: T, parameters: &[f64]) -> RegisterResult
where
T: AsyncEvaluatingBackend,
T: Sync,
{
match self{
QuantumProgram::ClassicalRegister{measurement, input_parameter_names } => {
if parameters.len() != input_parameter_names.len() { return Err(RoqoqoBackendError::GenericError{msg: format!("Wrong number of parameters {} parameters expected {} parameters given", input_parameter_names.len(), parameters.len())})};
let substituted_parameters: HashMap<String, f64> = input_parameter_names.iter().zip(parameters.iter()).map(|(key, value)| (key.clone(), *value)).collect();
let substituted_measurement = measurement.substitute_parameters(
substituted_parameters
)?;
backend.async_run_measurement_registers(&substituted_measurement).await
}
_ => Err(RoqoqoBackendError::GenericError{msg: "A quantum programm returning expectation values cannot be executed by `run_registers` use `run` instead".to_string()})
}
}
}
impl Display for QuantumProgram {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut s: String = String::new();
match self {
QuantumProgram::PauliZProduct { .. } => {
s.push_str("QuantumProgram::PauliZProduct");
}
QuantumProgram::CheatedPauliZProduct { .. } => {
s.push_str("QuantumProgram::CheatedPauliZProduct");
}
QuantumProgram::Cheated { .. } => {
s.push_str("QuantumProgram::Cheated");
}
QuantumProgram::ClassicalRegister { .. } => {
s.push_str("QuantumProgram::ClassicalRegister");
}
}
write!(f, "{s}")
}
}
impl crate::operations::SupportedVersion for QuantumProgram {
fn minimum_supported_roqoqo_version(&self) -> (u32, u32, u32) {
match self {
QuantumProgram::PauliZProduct { measurement, .. } => {
measurement.minimum_supported_roqoqo_version()
}
QuantumProgram::CheatedPauliZProduct { measurement, .. } => {
measurement.minimum_supported_roqoqo_version()
}
QuantumProgram::Cheated { measurement, .. } => {
measurement.minimum_supported_roqoqo_version()
}
QuantumProgram::ClassicalRegister { measurement, .. } => {
measurement.minimum_supported_roqoqo_version()
}
}
}
}