use super::SupportedVersion;
use std::collections::HashMap;
#[derive(Debug, Default, Clone, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "json_schema", derive(schemars::JsonSchema))]
pub struct SingleQubitOverrotationDescription {
gate: String,
theta_mean: f64,
theta_std: f64,
}
impl SupportedVersion for SingleQubitOverrotationDescription {
fn minimum_supported_roqoqo_version(&self) -> (u32, u32, u32) {
(1, 11, 0)
}
}
impl SingleQubitOverrotationDescription {
pub fn new(gate: &str, theta_mean: f64, theta_std: f64) -> Self {
SingleQubitOverrotationDescription {
gate: gate.to_string(),
theta_mean,
theta_std,
}
}
pub fn gate(&self) -> &String {
&self.gate
}
pub fn theta_mean(&self) -> f64 {
self.theta_mean
}
pub fn theta_std(&self) -> f64 {
self.theta_std
}
}
#[derive(Debug, Default, Clone, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "serialize",
serde(from = "SingleQubitOverrotationOnGateSerialize")
)]
#[cfg_attr(
feature = "serialize",
serde(into = "SingleQubitOverrotationOnGateSerialize")
)]
pub struct SingleQubitOverrotationOnGate {
single_qubit_overrotation: HashMap<(String, usize), SingleQubitOverrotationDescription>,
two_qubit_overrotation: HashMap<
(String, (usize, usize)),
(
SingleQubitOverrotationDescription,
SingleQubitOverrotationDescription,
),
>,
}
#[cfg(feature = "json_schema")]
impl schemars::JsonSchema for SingleQubitOverrotationOnGate {
fn schema_name() -> std::borrow::Cow<'static, str> {
"SingleQubitOverrotationOnGate".into()
}
fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
<SingleQubitOverrotationOnGateSerialize>::json_schema(generator)
}
}
#[cfg(feature = "serialize")]
type SingleQubitGateIndex = (String, usize);
#[cfg(feature = "serialize")]
type SingleQubitOverrotation = Vec<(SingleQubitGateIndex, SingleQubitOverrotationDescription)>;
#[cfg(feature = "serialize")]
type TwoQubitGateIndex = (String, (usize, usize));
#[cfg(feature = "serialize")]
type TwoQubitOverrotation = Vec<(
TwoQubitGateIndex,
(
SingleQubitOverrotationDescription,
SingleQubitOverrotationDescription,
),
)>;
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "json_schema",
derive(schemars::JsonSchema),
schemars(deny_unknown_fields)
)]
#[cfg(feature = "serialize")]
struct SingleQubitOverrotationOnGateSerialize {
single_qubit_overrotation: SingleQubitOverrotation,
two_qubit_overrotation: TwoQubitOverrotation,
}
#[cfg(feature = "serialize")]
impl From<SingleQubitOverrotationOnGate> for SingleQubitOverrotationOnGateSerialize {
fn from(value: SingleQubitOverrotationOnGate) -> Self {
let single_qubit_overrotation: SingleQubitOverrotation =
value.single_qubit_overrotation.into_iter().collect();
let two_qubit_overrotation: TwoQubitOverrotation =
value.two_qubit_overrotation.into_iter().collect();
SingleQubitOverrotationOnGateSerialize {
single_qubit_overrotation,
two_qubit_overrotation,
}
}
}
#[cfg(feature = "serialize")]
impl From<SingleQubitOverrotationOnGateSerialize> for SingleQubitOverrotationOnGate {
fn from(value: SingleQubitOverrotationOnGateSerialize) -> Self {
let single_qubit_overrotation: HashMap<
(String, usize),
SingleQubitOverrotationDescription,
> = value.single_qubit_overrotation.into_iter().collect();
let two_qubit_overrotation: HashMap<
(String, (usize, usize)),
(
SingleQubitOverrotationDescription,
SingleQubitOverrotationDescription,
),
> = value.two_qubit_overrotation.into_iter().collect();
SingleQubitOverrotationOnGate {
single_qubit_overrotation,
two_qubit_overrotation,
}
}
}
impl SupportedVersion for SingleQubitOverrotationOnGate {
fn minimum_supported_roqoqo_version(&self) -> (u32, u32, u32) {
(1, 11, 0)
}
}
impl SingleQubitOverrotationOnGate {
pub fn new() -> Self {
Self {
single_qubit_overrotation: HashMap::new(),
two_qubit_overrotation: HashMap::new(),
}
}
pub fn set_single_qubit_overrotation(
mut self,
gate: &str,
qubit: usize,
noise_description: SingleQubitOverrotationDescription,
) -> Self {
self.single_qubit_overrotation
.insert((gate.to_string(), qubit), noise_description);
self
}
pub fn get_single_qubit_overrotation(
&self,
gate: &str,
qubit: usize,
) -> Option<&SingleQubitOverrotationDescription> {
self.single_qubit_overrotation
.get(&(gate.to_string(), qubit))
}
pub fn set_two_qubit_overrotation(
mut self,
gate: &str,
control: usize,
target: usize,
noise_description: (
SingleQubitOverrotationDescription,
SingleQubitOverrotationDescription,
),
) -> Self {
self.two_qubit_overrotation
.insert((gate.to_string(), (control, target)), noise_description);
self
}
pub fn get_two_qubit_overrotation(
&self,
gate: &str,
control: usize,
target: usize,
) -> Option<&(
SingleQubitOverrotationDescription,
SingleQubitOverrotationDescription,
)> {
self.two_qubit_overrotation
.get(&(gate.to_string(), (control, target)))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "json_schema")]
use jsonschema::Validator;
#[test]
fn test_singe_qubit_overrotation_on_gate_single() {
let noise_descp = SingleQubitOverrotationDescription::new("RotateZ", 1.0, 1.0);
let mut noise_model = SingleQubitOverrotationOnGate::new();
noise_model = noise_model.set_single_qubit_overrotation("RotateX", 0, noise_descp.clone());
assert_eq!(
noise_model.get_single_qubit_overrotation("RotateX", 0),
Some(&noise_descp)
);
}
#[test]
fn test_overrotation_on_gate_two() {
let mut noise_model = SingleQubitOverrotationOnGate::new();
let noise_descp = SingleQubitOverrotationDescription::new("RotateZ", 1.0, 1.0);
noise_model = noise_model.set_two_qubit_overrotation(
"CNOT",
0,
1,
(noise_descp.clone(), noise_descp.clone()),
);
assert_eq!(
noise_model.get_two_qubit_overrotation("CNOT", 0, 1),
Some(&(noise_descp.clone(), noise_descp.clone()))
);
}
#[cfg(feature = "serialize")]
#[test]
fn test_json_serialization() {
let noise_descp = SingleQubitOverrotationDescription::new("RotateZ", 1.0, 1.0);
let mut noise_model = SingleQubitOverrotationOnGate::new();
noise_model = noise_model.set_single_qubit_overrotation("RotateX", 0, noise_descp.clone());
let json_str = serde_json::to_string(&noise_model).unwrap();
let deserialized_noise_model: SingleQubitOverrotationOnGate =
serde_json::from_str(&json_str).unwrap();
assert_eq!(noise_model, deserialized_noise_model);
}
#[cfg(feature = "json_schema")]
#[test]
fn test_json_schema_feature() {
let noise_descp = SingleQubitOverrotationDescription::new("RotateZ", 1.0, 1.0);
let mut model = SingleQubitOverrotationOnGate::new();
model = model.set_single_qubit_overrotation("RotateX", 0, noise_descp.clone());
let schema = schemars::schema_for!(SingleQubitOverrotationOnGate);
let schema_checker =
Validator::new(&serde_json::to_value(&schema).unwrap()).expect("schema is valid");
let value = serde_json::to_value(model).unwrap();
let val = match value {
serde_json::Value::Object(ob) => ob,
_ => panic!(),
};
let value: serde_json::Value = serde_json::to_value(val).unwrap();
let validation = schema_checker.validate(&value);
assert!(validation.is_ok());
}
}