-
Notifications
You must be signed in to change notification settings - Fork 2.7k
[WIP] PauliProductMeasurement
instruction
#15126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b3b80a7
a62a155
ed9831e
3d8556f
703c35b
d3d0557
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -16,7 +16,9 @@ use std::sync::Arc; | |||||
use std::{fmt, vec}; | ||||||
|
||||||
use crate::circuit_data::CircuitData; | ||||||
use crate::imports::{BARRIER, DELAY, MEASURE, RESET, get_std_gate_class}; | ||||||
use crate::imports::{ | ||||||
BARRIER, DELAY, MEASURE, PAULI_PRODUCT_MEASUREMENT, RESET, get_std_gate_class, | ||||||
}; | ||||||
use crate::imports::{DEEPCOPY, QUANTUM_CIRCUIT, UNITARY_GATE}; | ||||||
use crate::parameter::parameter_expression::{ | ||||||
ParameterExpression, PyParameter, PyParameterExpression, | ||||||
|
@@ -275,6 +277,7 @@ pub enum OperationRef<'a> { | |||||
Instruction(&'a PyInstruction), | ||||||
Operation(&'a PyOperation), | ||||||
Unitary(&'a UnitaryGate), | ||||||
PPM(&'a PauliProductMeasurement), | ||||||
} | ||||||
|
||||||
impl Operation for OperationRef<'_> { | ||||||
|
@@ -287,6 +290,7 @@ impl Operation for OperationRef<'_> { | |||||
Self::Instruction(instruction) => instruction.name(), | ||||||
Self::Operation(operation) => operation.name(), | ||||||
Self::Unitary(unitary) => unitary.name(), | ||||||
Self::PPM(ppm) => ppm.name(), | ||||||
} | ||||||
} | ||||||
#[inline] | ||||||
|
@@ -298,6 +302,7 @@ impl Operation for OperationRef<'_> { | |||||
Self::Instruction(instruction) => instruction.num_qubits(), | ||||||
Self::Operation(operation) => operation.num_qubits(), | ||||||
Self::Unitary(unitary) => unitary.num_qubits(), | ||||||
Self::PPM(ppm) => ppm.num_qubits(), | ||||||
} | ||||||
} | ||||||
#[inline] | ||||||
|
@@ -309,6 +314,7 @@ impl Operation for OperationRef<'_> { | |||||
Self::Instruction(instruction) => instruction.num_clbits(), | ||||||
Self::Operation(operation) => operation.num_clbits(), | ||||||
Self::Unitary(unitary) => unitary.num_clbits(), | ||||||
Self::PPM(ppm) => ppm.num_clbits(), | ||||||
} | ||||||
} | ||||||
#[inline] | ||||||
|
@@ -320,6 +326,7 @@ impl Operation for OperationRef<'_> { | |||||
Self::Instruction(instruction) => instruction.num_params(), | ||||||
Self::Operation(operation) => operation.num_params(), | ||||||
Self::Unitary(unitary) => unitary.num_params(), | ||||||
Self::PPM(ppm) => ppm.num_params(), | ||||||
} | ||||||
} | ||||||
#[inline] | ||||||
|
@@ -331,6 +338,7 @@ impl Operation for OperationRef<'_> { | |||||
Self::Instruction(instruction) => instruction.control_flow(), | ||||||
Self::Operation(operation) => operation.control_flow(), | ||||||
Self::Unitary(unitary) => unitary.control_flow(), | ||||||
Self::PPM(ppm) => ppm.control_flow(), | ||||||
} | ||||||
} | ||||||
#[inline] | ||||||
|
@@ -342,6 +350,7 @@ impl Operation for OperationRef<'_> { | |||||
OperationRef::Instruction(instruction) => instruction.blocks(), | ||||||
OperationRef::Operation(operation) => operation.blocks(), | ||||||
Self::Unitary(unitary) => unitary.blocks(), | ||||||
Self::PPM(ppm) => ppm.blocks(), | ||||||
} | ||||||
} | ||||||
#[inline] | ||||||
|
@@ -353,6 +362,7 @@ impl Operation for OperationRef<'_> { | |||||
Self::Instruction(instruction) => instruction.matrix(params), | ||||||
Self::Operation(operation) => operation.matrix(params), | ||||||
Self::Unitary(unitary) => unitary.matrix(params), | ||||||
Self::PPM(ppm) => ppm.matrix(params), | ||||||
} | ||||||
} | ||||||
#[inline] | ||||||
|
@@ -364,6 +374,7 @@ impl Operation for OperationRef<'_> { | |||||
Self::Instruction(instruction) => instruction.definition(params), | ||||||
Self::Operation(operation) => operation.definition(params), | ||||||
Self::Unitary(unitary) => unitary.definition(params), | ||||||
Self::PPM(ppm) => ppm.definition(params), | ||||||
} | ||||||
} | ||||||
#[inline] | ||||||
|
@@ -375,6 +386,7 @@ impl Operation for OperationRef<'_> { | |||||
Self::Instruction(instruction) => instruction.directive(), | ||||||
Self::Operation(operation) => operation.directive(), | ||||||
Self::Unitary(unitary) => unitary.directive(), | ||||||
Self::PPM(ppm) => ppm.directive(), | ||||||
} | ||||||
} | ||||||
|
||||||
|
@@ -388,6 +400,7 @@ impl Operation for OperationRef<'_> { | |||||
Self::Instruction(instruction) => instruction.matrix_as_static_1q(params), | ||||||
Self::Operation(operation) => operation.matrix_as_static_1q(params), | ||||||
Self::Unitary(unitary) => unitary.matrix_as_static_1q(params), | ||||||
Self::PPM(ppm) => ppm.matrix_as_static_1q(params), | ||||||
} | ||||||
} | ||||||
} | ||||||
|
@@ -2890,3 +2903,82 @@ impl UnitaryGate { | |||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
/// This class represents a PauliProductMeasurement instruction. | ||||||
#[derive(Clone, Debug)] | ||||||
#[repr(align(8))] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the current format I don't think we need this, since bool and u8 are both a byte long. But if we change to |
||||||
pub struct PauliProductMeasurement { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll need to construct the PPMs in the Rust Litinski transformation code, which currently outputs the Pauli in a sparse string format (sign, Paulistring, indices). If we use ZX bits as internal representation we'll also need a converter from Pauli string to ZX in Rust. |
||||||
/// The z-component of the pauli. | ||||||
pub z: Vec<bool>, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there alternatives to storing boolean vectors, i.e. 1 byte per term if we'd only need 1 bit? E.g. the |
||||||
/// The x-component of the pauli. | ||||||
pub x: Vec<bool>, | ||||||
/// The phase of the pauli. This is an integer modulo 4. | ||||||
pub phase: u8, | ||||||
} | ||||||
|
||||||
impl Operation for PauliProductMeasurement { | ||||||
fn name(&self) -> &str { | ||||||
"PauliProductMeasurement" | ||||||
} | ||||||
fn num_qubits(&self) -> u32 { | ||||||
self.z.len() as u32 | ||||||
} | ||||||
fn num_clbits(&self) -> u32 { | ||||||
1 | ||||||
} | ||||||
fn num_params(&self) -> u32 { | ||||||
0 | ||||||
} | ||||||
fn control_flow(&self) -> bool { | ||||||
false | ||||||
} | ||||||
fn blocks(&self) -> Vec<CircuitData> { | ||||||
vec![] | ||||||
} | ||||||
fn matrix(&self, _params: &[Param]) -> Option<Array2<Complex64>> { | ||||||
None | ||||||
} | ||||||
fn definition(&self, _params: &[Param]) -> Option<CircuitData> { | ||||||
// Similarly to UnitaryGate, we do not provide the actual decomposition here. | ||||||
// Instead, the HighLevelSynthesis transpiler pass is modified to call the | ||||||
// relevant synthesis function when requiring the definition for a | ||||||
// PauliProudctMeasurement. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
None | ||||||
} | ||||||
fn directive(&self) -> bool { | ||||||
false | ||||||
} | ||||||
fn matrix_as_static_1q(&self, _params: &[Param]) -> Option<[[Complex64; 2]; 2]> { | ||||||
None | ||||||
} | ||||||
|
||||||
fn matrix_as_nalgebra_1q(&self, _params: &[Param]) -> Option<Matrix2<Complex64>> { | ||||||
None | ||||||
} | ||||||
} | ||||||
|
||||||
impl PauliProductMeasurement { | ||||||
pub fn create_py_op(&self, py: Python, label: Option<&str>) -> PyResult<Py<PyAny>> { | ||||||
let z = PyList::new(py, &self.z)?; | ||||||
let x = PyList::new(py, &self.x)?; | ||||||
let phase = self.phase; | ||||||
let py_label = if let Some(label) = label { | ||||||
label.into_py_any(py)? | ||||||
} else { | ||||||
py.None() | ||||||
}; | ||||||
|
||||||
let gate = PAULI_PRODUCT_MEASUREMENT | ||||||
.get_bound(py) | ||||||
.call_method1(intern!(py, "_from_pauli_data"), (z, x, phase, py_label))?; | ||||||
Ok(gate.unbind()) | ||||||
} | ||||||
} | ||||||
|
||||||
impl PartialEq for PauliProductMeasurement { | ||||||
fn eq(&self, other: &Self) -> bool { | ||||||
self.x == other.x && self.z == other.z && self.phase == other.phase | ||||||
} | ||||||
} | ||||||
|
||||||
impl Eq for PauliProductMeasurement {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we spell
PPM
out? No other gates are abbreviated and it'll be more consistent withPauliEvolutionGate
orPauliRotationGate
.