Skip to content

Commit

Permalink
Added devices unittests and separated OperatePragmaNoise into Operate…
Browse files Browse the repository at this point in the history
…PragmaNoise and OperatePragmaNoiseProba
  • Loading branch information
kbarkhqs committed Sep 2, 2021
1 parent 6192eb3 commit a480db1
Show file tree
Hide file tree
Showing 14 changed files with 408 additions and 159 deletions.
22 changes: 15 additions & 7 deletions qoqo-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,6 @@ pub fn wrap(
let py = gil.python();
Ok(self.internal.superoperator().unwrap().to_pyarray(py).to_owned())
}
/// Returns the probability associated with the noise operation
///
/// Returns:
/// CalculatorFloat
pub fn probability(&self) -> CalculatorFloatWrapper{
CalculatorFloatWrapper{cf_internal: self.internal.probability().clone()}
}
/// Return the power of the noise gate
///
/// Args:
Expand All @@ -146,6 +139,20 @@ pub fn wrap(
} else {
TokenStream::new()
};
let operate_pragma_noise_proba_quote =
if attribute_arguments.contains("OperatePragmaNoiseProba") {
quote! {
/// Returns the probability associated with the noise operation
///
/// Returns:
/// CalculatorFloat
pub fn probability(&self) -> CalculatorFloatWrapper{
CalculatorFloatWrapper{cf_internal: self.internal.probability().clone()}
}
}
} else {
TokenStream::new()
};
let operate_single_qubit_quote = if attribute_arguments.contains("OperateSingleQubit") {
quote! {
/// Return the qubit the operation acts on
Expand Down Expand Up @@ -358,6 +365,7 @@ pub fn wrap(
#rotate_quote
#operate_pragma_quote
#operate_pragma_noise_quote
#operate_pragma_noise_proba_quote
#define_quote
#operate_constant_gate_quote
fn __format__(&self, _format_spec: &str) -> PyResult<String> {
Expand Down
49 changes: 34 additions & 15 deletions qoqo/src/operations/pragma_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,13 @@ pub struct PragmaStopDecompositionBlock {
qubits: Vec<usize>,
}

#[wrap(Operate, OperateSingleQubit, OperatePragma, OperatePragmaNoise)]
#[wrap(
Operate,
OperateSingleQubit,
OperatePragma,
OperatePragmaNoise,
OperatePragmaNoiseProba
)]
/// The damping PRAGMA noise operation.
///
/// This PRAGMA operation applies a pure damping error corresponding to zero temperature environments.
Expand Down Expand Up @@ -666,7 +672,13 @@ pub struct PragmaDamping {
// }
// }

#[wrap(Operate, OperateSingleQubit, OperatePragma, OperatePragmaNoise)]
#[wrap(
Operate,
OperateSingleQubit,
OperatePragma,
OperatePragmaNoise,
OperatePragmaNoiseProba
)]
/// The depolarising PRAGMA noise operation.
///
/// This PRAGMA operation applies a depolarising error corresponding to infinite temperature environments.
Expand Down Expand Up @@ -719,7 +731,13 @@ pub struct PragmaDepolarising {
// }
// }

#[wrap(Operate, OperateSingleQubit, OperatePragma, OperatePragmaNoise)]
#[wrap(
Operate,
OperateSingleQubit,
OperatePragma,
OperatePragmaNoise,
OperatePragmaNoiseProba
)]
/// The dephasing PRAGMA noise operation.
///
/// This PRAGMA operation applies a pure dephasing error.
Expand Down Expand Up @@ -772,7 +790,13 @@ pub struct PragmaDephasing {
// }
// }

#[wrap(Operate, OperateSingleQubit, OperatePragma, OperatePragmaNoise)]
#[wrap(
Operate,
OperateSingleQubit,
OperatePragma,
OperatePragmaNoise,
OperatePragmaNoiseProba
)]
/// The random noise PRAGMA operation.
///
/// This PRAGMA operation applies a pure damping error corresponding to zero temperature environments.
Expand Down Expand Up @@ -918,11 +942,7 @@ impl PragmaGeneralNoiseWrapper {
/// Returns:
/// self: The new PragmaGeneralNoise.
#[new]
fn new(
qubit: usize,
gate_time: Py<PyAny>,
rates: Py<PyAny>,
) -> PyResult<Self> {
fn new(qubit: usize, gate_time: Py<PyAny>, rates: Py<PyAny>) -> PyResult<Self> {
let rates_casted: Vec<f64> =
Python::with_gil(|py| -> Vec<f64> { Vec::extract(rates.as_ref(py)).unwrap() });
let rates_array = Array::from_shape_vec((3, 3), rates_casted).unwrap();
Expand All @@ -933,7 +953,7 @@ impl PragmaGeneralNoiseWrapper {
)
})
})?;

Ok(Self {
internal: PragmaGeneralNoise::new(qubit, gate_time_cf, rates_array),
})
Expand Down Expand Up @@ -979,11 +999,10 @@ impl PragmaGeneralNoiseWrapper {
/// np.ndarray: The rates of the PRAGMA operation.
fn superoperator(&self) -> PyResult<Py<PyArray2<f64>>> {
Python::with_gil(|py| -> PyResult<Py<PyArray2<f64>>> {
match self.internal
.superoperator(){
Ok(x) => Ok(x.to_pyarray(py).to_owned()),
Err(err) => Err(PyRuntimeError::new_err(format!("{:?}", err)))
}
match self.internal.superoperator() {
Ok(x) => Ok(x.to_pyarray(py).to_owned()),
Err(err) => Err(PyRuntimeError::new_err(format!("{:?}", err))),
}
})
}

Expand Down
25 changes: 21 additions & 4 deletions qoqo/tests/integration/operations/pragma_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,6 @@ fn test_pyo3_tags_multi_overrotation(input_measurement: Operation, tag_name: &st

/// Test tags function for Pragmas that are also SingleQubitGates
#[test_case(Operation::from(PragmaActiveReset::new(0)), "PragmaActiveReset"; "PragmaActiveReset")]
#[test_case(Operation::from(PragmaGeneralNoise::new(0, CalculatorFloat::from(0.005), operators())), "PragmaGeneralNoise"; "PragmaGeneralNoise")]
#[test_case(Operation::from(PragmaConditional::new(String::from("ro"), 1, create_circuit())), "PragmaConditional"; "PragmaConditional")]
fn test_pyo3_tags_single(input_measurement: Operation, tag_name: &str) {
pyo3::prepare_freethreaded_python();
Expand All @@ -823,6 +822,25 @@ fn test_pyo3_tags_single(input_measurement: Operation, tag_name: &str) {
assert_eq!(tags_op, tags_param);
}

/// Test tags function for PragmaGeneralNoise
#[test_case(Operation::from(PragmaGeneralNoise::new(0, CalculatorFloat::from(0.005), operators())), "PragmaGeneralNoise"; "PragmaGeneralNoise")]
fn test_pyo3_tags_general_noise(input_measurement: Operation, tag_name: &str) {
pyo3::prepare_freethreaded_python();
let gil = pyo3::Python::acquire_gil();
let py = gil.python();
let operation = convert_operation_to_pyobject(input_measurement).unwrap();
let to_tag = operation.call_method0(py, "tags").unwrap();
let tags_op: &Vec<&str> = &Vec::extract(to_tag.as_ref(py)).unwrap();
let tags_param: &[&str] = &[
"Operation",
"SingleQubitOperation",
"PragmaOperation",
"PragmaNoiseOperation",
tag_name,
];
assert_eq!(tags_op, tags_param);
}

/// Test tags function for Noise Pragmas
#[test_case(Operation::from(PragmaDamping::new(0, CalculatorFloat::from(0.005), CalculatorFloat::from(0.02))), "PragmaDamping"; "PragmaDamping")]
#[test_case(Operation::from(PragmaDepolarising::new(0, CalculatorFloat::from(0.005), CalculatorFloat::from(0.02))), "PragmaDepolarising"; "PragmaDepolarising")]
Expand All @@ -840,6 +858,7 @@ fn test_pyo3_tags_noise(input_measurement: Operation, tag_name: &str) {
"SingleQubitOperation",
"PragmaOperation",
"PragmaNoiseOperation",
"PragmaNoiseProbaOperation",
tag_name,
];
assert_eq!(tags_op, tags_param);
Expand Down Expand Up @@ -2373,9 +2392,7 @@ fn test_pyo3_new_general_noise() {
let convert_to_get_operators = convert_operation_to_pyobject(to_get_operators)
.unwrap()
.clone();
let operators_op = convert_to_get_operators
.call_method0(py, "rates")
.unwrap();
let operators_op = convert_to_get_operators.call_method0(py, "rates").unwrap();

let new_op = operation
.call1((0, 0.005, operators_op.clone()))
Expand Down
9 changes: 9 additions & 0 deletions roqoqo-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ pub fn derive_operate_noise_pragmas(input: proc_macro::TokenStream) -> proc_macr
operate_unitary::dispatch_struct_enum_operate_noise_pragma(parsed_input).into()
}

/// Derive macro for the [roqoqo::OperatePragmaNoiseProba] trait
#[proc_macro_derive(OperatePragmaNoiseProba)]
pub fn derive_operate_noise_proba_pragmas(
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let parsed_input = parse_macro_input!(input as DeriveInput);
operate_unitary::dispatch_struct_enum_operate_noise_proba_pragma(parsed_input).into()
}

/// Derive macro for the [roqoqo::OperateGate] trait
#[proc_macro_derive(OperateGate)]
pub fn derive_operate_gate(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
Expand Down
36 changes: 27 additions & 9 deletions roqoqo-derive/src/operate_unitary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,11 +441,6 @@ fn operate_noise_pragma_enum(de: DataEnum, ident: Ident) -> TokenStream {
&#ident::#vident(ref inner) => {OperatePragmaNoise::superoperator(&(*inner))},
}
});
let match_proba_quotes = variants_with_type.clone().map(|(vident, _, _)| {
quote! {
&#ident::#vident(ref inner) => inner.probability(),
}
});
let match_pow_quotes = variants_with_type.map(|(vident, _, _)| {
quote! {
&#ident::#vident(ref inner) => #ident::#vident(OperatePragmaNoise::powercf(&(*inner), power)),
Expand All @@ -460,15 +455,38 @@ fn operate_noise_pragma_enum(de: DataEnum, ident: Ident) -> TokenStream {
_ => panic!("Unexpectedly cannot match variant")
}
}
fn probability(&self) -> CalculatorFloat{
fn powercf(&self, power: CalculatorFloat) -> #ident {
match self{
#(#match_proba_quotes)*
#(#match_pow_quotes)*
_ => panic!("Unexpectedly cannot match variant")
}
}
fn powercf(&self, power: CalculatorFloat) -> #ident {
}
};
q
}

pub fn dispatch_struct_enum_operate_noise_proba_pragma(input: DeriveInput) -> TokenStream {
let ident = input.ident;
match input.data {
Data::Enum(de) => operate_noise_proba_pragma_enum(de, ident),
_ => panic!("OperatePragmaNoiseProba can only be derived on enums"),
}
}

fn operate_noise_proba_pragma_enum(de: DataEnum, ident: Ident) -> TokenStream {
let variants_with_type = extract_variants_with_types(de).into_iter();
let match_proba_quotes = variants_with_type.clone().map(|(vident, _, _)| {
quote! {
&#ident::#vident(ref inner) => inner.probability(),
}
});
let q = quote! {
#[automatically_derived]
impl OperatePragmaNoiseProba for #ident{
fn probability(&self) -> CalculatorFloat{
match self{
#(#match_pow_quotes)*
#(#match_proba_quotes)*
_ => panic!("Unexpectedly cannot match variant")
}
}
Expand Down
30 changes: 29 additions & 1 deletion roqoqo/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ struct Visitor {
pragma_operations: Vec<Ident>,
// Identifiers of structs belonging to PragmaNoiseOperation enum
pragma_noise_operations: Vec<Ident>,
// Identifiers of structs belonging to PragmaNoiseProbaOperation enum
pragma_noise_proba_operations: Vec<Ident>,
// Identifiers of structs belonging to GateOperation enum
gate_operations: Vec<Ident>,
// Identifiers of structs belonging to Rotation enum
Expand All @@ -59,6 +61,7 @@ impl Visitor {
multi_qubit_operations: Vec::new(),
pragma_operations: Vec::new(),
pragma_noise_operations: Vec::new(),
pragma_noise_proba_operations: Vec::new(),
gate_operations: Vec::new(),
rotations: Vec::new(),
definitions: Vec::new(),
Expand Down Expand Up @@ -145,6 +148,13 @@ impl<'ast> Visit<'ast> for Visitor {
{
self.pragma_noise_operations.push(i.ident.clone());
}
if parsed_arguments.contains("Operate")
&& parsed_arguments.contains("OperatePragma")
&& parsed_arguments.contains("OperatePragmaNoise")
&& parsed_arguments.contains("OperatePragmaNoiseProba")
{
self.pragma_noise_proba_operations.push(i.ident.clone());
}
if parsed_arguments.contains("Operate") && parsed_arguments.contains("OperateGate")
{
self.gate_operations.push(i.ident.clone());
Expand Down Expand Up @@ -219,6 +229,9 @@ impl<'ast> Visit<'ast> for Visitor {
if trait_name.as_str() == "OperatePragmaNoise" {
self.pragma_noise_operations.push(id.clone());
}
if trait_name.as_str() == "OperatePragmaNoiseProba" {
self.pragma_noise_proba_operations.push(id.clone());
}
if trait_name.as_str() == "OperateMultiQubitGate" {
self.two_qubit_gate_operations.push(id);
}
Expand Down Expand Up @@ -286,13 +299,21 @@ fn main() {
#v(#v)}
});
// Construct TokenStreams for variants of pragma enum
let pragma_noise_operations_quotes = vis.pragma_noise_operations.into_iter().map(|v| {
let pragma_noise_operations_quotes = vis.pragma_noise_operations.clone().into_iter().map(|v| {
let msg = format!("Variant for {}", v);
quote! {
#[doc = #msg]
#v(#v)}
});
// Construct TokenStreams for variants of pragma enum
let pragma_noise_proba_operations_quotes =
vis.pragma_noise_proba_operations.into_iter().map(|v| {
let msg = format!("Variant for {}", v);
quote! {
#[doc = #msg]
#v(#v)}
});
// Construct TokenStreams for variants of pragma enum
let gate_operations_quotes = vis.gate_operations.into_iter().map(|v| {
let msg = format!("Variant for {}", v);
quote! {
Expand Down Expand Up @@ -392,6 +413,13 @@ fn main() {
#(#pragma_noise_operations_quotes),*
}

/// Enum of all Operations implementing [OperatePragmaNoiseProba]
#[derive(Debug, Clone, PartialEq, InvolveQubits, Operate, OperateTryFromEnum, Substitute, OperatePragma, OperatePragmaNoise, OperatePragmaNoiseProba)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub enum PragmaNoiseProbaOperation {
#(#pragma_noise_proba_operations_quotes),*
}

/// Enum of all Operations implementing [OperateGate]
#[derive(Debug, Clone, PartialEq, InvolveQubits, Operate, OperateTryFromEnum, Substitute, OperateGate)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
Expand Down
Loading

0 comments on commit a480db1

Please sign in to comment.