Skip to content

Add confusion map support to Pauli Measurement Gate #7373

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions cirq-core/cirq/ops/pauli_measurement_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

from typing import Any, cast, Iterable, Iterator, Mapping, Sequence, TYPE_CHECKING

import numpy as np

from cirq import protocols, value
from cirq.ops import (
dense_pauli_string as dps,
Expand All @@ -42,6 +44,7 @@ def __init__(
self,
observable: cirq.BaseDensePauliString | Iterable[cirq.Pauli],
key: str | cirq.MeasurementKey = '',
confusion_map: dict[tuple[int, ...], np.ndarray] | None = None,
) -> None:
"""Inits PauliMeasurementGate.

Expand All @@ -51,6 +54,9 @@ def __init__(
If you wish to measure pauli observables with coefficient -1,
then pass a `cirq.DensePauliString` as observable.
key: The string key of the measurement.
confusion_map: A map of qubit index sets (using indices in the
operation generated from this gate) to the 2D confusion matrix
for those qubits. Indices not included use the identity.

Raises:
ValueError: If the observable is empty.
Expand All @@ -73,6 +79,9 @@ def __init__(
self._mkey = (
key if isinstance(key, value.MeasurementKey) else value.MeasurementKey(name=key)
)
self._confusion_map = confusion_map or {}
if any(x >= len(self._observable) for idx in self._confusion_map for x in idx):
raise ValueError('Confusion matrices have index out of bounds.')

@property
def key(self) -> str:
Expand All @@ -82,6 +91,10 @@ def key(self) -> str:
def mkey(self) -> cirq.MeasurementKey:
return self._mkey

@property
def confusion_map(self) -> dict[tuple[int, ...], np.ndarray]:
return self._confusion_map

def _qid_shape_(self) -> tuple[int, ...]:
return (2,) * len(self._observable)

Expand All @@ -92,7 +105,7 @@ def with_key(self, key: str | cirq.MeasurementKey) -> PauliMeasurementGate:
"""Creates a pauli measurement gate with a new key but otherwise identical."""
if key == self.key:
return self
return PauliMeasurementGate(self._observable, key=key)
return PauliMeasurementGate(self._observable, key=key, confusion_map=self.confusion_map)

def _with_key_path_(self, path: tuple[str, ...]) -> PauliMeasurementGate:
return self.with_key(self.mkey._with_key_path_(path))
Expand All @@ -118,7 +131,7 @@ def with_observable(
else dps.DensePauliString(observable)
) == self._observable:
return self
return PauliMeasurementGate(observable, key=self.key)
return PauliMeasurementGate(observable, key=self.key, confusion_map=self.confusion_map)

def _is_measurement_(self) -> bool:
return True
Expand Down
Loading