-
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?
Conversation
Co-authored-by: Alexander Ivrii <[email protected]>
Pull Request Test Coverage Report for Build 18442497358Warning: This coverage report may be inaccurate.This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.
Details
💛 - Coveralls |
* Conversions between rust and python classes * Synthesis of PauliProductMeasurement instructions * Exposing synthesis function to python * Usage of synthesis function in HLS * QPY support * Some additional python tests
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.
The overall structure LGTM, my main comment is about the internal Pauli representation. Do we want to generally adopt a dense ZX formulation for Cliffords and PBC? If yes, we (1) need to ensure we can build the PPMs from the string output of the Litinski transformation, and (2) it would be nice to investigate bitpacking (e.g. bitvec
package?).
""" | ||
Args: | ||
pauli: A tensor product of Pauli operators defining the measurement, | ||
for example ``Pauli("XY")`` or ``Pauli("-XYIZ)``. |
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.
for example ``Pauli("XY")`` or ``Pauli("-XYIZ)``. | |
for example ``Pauli("XY")`` or ``Pauli("-XYIZ")``. |
While Paulis involving "I"-terms are fully supported, it is recommended to remove | ||
"I"-terms from the Pauli when creating a ``PauliProductMeasurement`` instruction, |
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.
While Paulis involving "I"-terms are fully supported, it is recommended to remove | |
"I"-terms from the Pauli when creating a ``PauliProductMeasurement`` instruction, | |
While Paulis involving ``"I"``-terms are fully supported, it is recommended to remove | |
``"I"``-terms from the Pauli when creating a ``PauliProductMeasurement`` instruction, |
""" | ||
|
||
if not isinstance(pauli, Pauli): |
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.
We generally don't have these type checks in the circuit library -- the type hint is clear here so it's on the user to provide the right type.
with self.assertRaises(CircuitError): | ||
_ = PauliProductMeasurement(Pauli(p)) | ||
|
||
@data("", "II", "-III") |
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.
Arguably ""
is not the identity string 😉 A separate error here seems better.
qc3.append(PauliProductMeasurement(Pauli("XZ")), [4, 1], [0]) | ||
|
||
qc4 = QuantumCircuit(5, 2) | ||
qc4.append(PauliProductMeasurement(Pauli("ZX")), [4, 1], [1]) |
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.
It would be good to add a case here that checks that reverting the Pauli labels and qubit indices evaluates to True
.
Instruction(&'a PyInstruction), | ||
Operation(&'a PyOperation), | ||
Unitary(&'a UnitaryGate), | ||
PPM(&'a 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 with PauliEvolutionGate
or PauliRotationGate
.
#[repr(align(8))] | ||
pub struct PauliProductMeasurement { | ||
/// The z-component of the pauli. | ||
pub z: Vec<bool>, |
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.
Are there alternatives to storing boolean vectors, i.e. 1 byte per term if we'd only need 1 bit? E.g. the bitvec
package seems to have a convenient interface. I assume @jakelishman has some opinions here 🙂
|
||
/// 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 comment
The 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 bitvec
or some bitpacking we might need to keep it?
/// This class represents a PauliProductMeasurement instruction. | ||
#[derive(Clone, Debug)] | ||
#[repr(align(8))] | ||
pub struct 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.
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.
with self.assertRaises(CircuitError): | ||
_ = PauliProductMeasurement(Pauli("XYZ")).inverse() | ||
|
||
def test_qpy(self): |
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.
+1 for thinking of qpy 👍🏻 I guess for qasm export it'll just define the instruction?
Summary
Adds rust and python support for
PauliProductMeasurement
instructions. This is a fundamental operation in fault-tolerant quantum computing [1].Close #15104
Co-authored by @alexanderivrii
References:
Details and comments
The implementation is similar to the existing handling of unitary gates.
In rust:
PauliProductMeasurement
forPackedOperationType
. This increases the total number of types to7
.PauliProductMeasurement
defined inoperations.rs
. Currently it storesbut we are considering bitpacking the data structure.
There is a new variant
PPM
ofOperationRef
.The
synthesis
crate contains a functionsynthesize_ppm
, which is used inHighLevelSynthesis
transpiler pass to synthesizePauliProductMeasurement
instructions (this is very similar to handling unitary gates) and is also exposed to Python (allowing to extractdefinition
on the python side).In python:
PauliProductMeasurement
, which can be instantiated from aPauli
object:Internally, the pauli data
(pauli.z, pauli.x, pauli.phase)
is stored in theparams
field, allowing to easily pass it down to rust.QPY serialization works
Visualization is done using the
label
attribute. Currently this just draws a box over relevant quantum and classical bits.Default and custom labels are preserved correct;y
Note that we support pauli product measurement instructions based on Paulis with some "I"-terms (except for all-"I"), since we believe that this might simplify user workflows. However, for efficiency it would be better for the users to avoid creating "I"s, and we will try to document this clearly both in the docstring and the release note
ToDo (in this PR)
SparseObservable
.ToDo (in follow-ups)
LitinskiTransformation
pass to produce PPMs in addition to PPRs (pauli product rotations).