Skip to content

Commit

Permalink
Merge branch 'main' into 0.2
Browse files Browse the repository at this point in the history
  • Loading branch information
andrea-pasquale committed Jan 9, 2025
2 parents efa4ad5 + 293e2a9 commit 07757c8
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 116 deletions.
12 changes: 0 additions & 12 deletions .github/pull_request_template.md

This file was deleted.

4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ repos:
- id: isort
args: ["--profile", "black"]
- repo: https://github.com/asottile/pyupgrade
rev: v3.19.0
rev: v3.19.1
hooks:
- id: pyupgrade
- repo: https://github.com/hadialqattan/pycln
rev: v2.4.0
rev: v2.5.0
hooks:
- id: pycln
args:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "qibocal"
version = "0.1.1"
version = "0.1.2"
description = "Qibo's quantum calibration, characterization and validation module."
authors = ["The Qibo team"]
license = "Apache License 2.0"
Expand Down
1 change: 1 addition & 0 deletions src/qibocal/protocols/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,6 @@
"standard_rb_2q",
"standard_rb_2q_inter",
"optimize_two_qubit_gate",
"mermin",
"ramsey_zz",
]
142 changes: 50 additions & 92 deletions src/qibocal/protocols/readout_mitigation_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,18 @@
from qibo import gates
from qibo.backends import get_backend
from qibo.models import Circuit
from qibolab import PulseSequence
from scipy.sparse import lil_matrix

from qibocal.auto.operation import Data, Parameters, QubitId, Results, Routine
from qibocal.auto.transpile import dummy_transpiler, execute_transpiled_circuit
from qibocal.calibration import CalibrationPlatform
from qibocal.config import log

from .utils import calculate_frequencies, computational_basis


@dataclass
class ReadoutMitigationMatrixParameters(Parameters):
"""ReadoutMitigationMatrix matrix inputs."""

pulses: Optional[bool] = True
"""Get readout mitigation matrix using pulses. If False gates will be used."""
nshots: Optional[int] = None
"""Number of shots."""
relaxation_time: Optional[int] = None
Expand All @@ -36,10 +31,14 @@ class ReadoutMitigationMatrixResults(Results):
field(default_factory=dict)
)
"""Readout mitigation matrices (inverse of measurement matrix)."""
measurement_matrix: dict[tuple[QubitId, ...], npt.NDArray[np.float64]] = field(
default_factory=dict
)
"""Matrix containing measurement matrices for each state."""


ReadoutMitigationMatrixType = np.dtype(
[
("state", int),
("frequency", np.float64),
]
)


ReadoutMitigationMatrixId = tuple[Tuple[QubitId, ...], str, str]
Expand All @@ -61,51 +60,6 @@ class ReadoutMitigationMatrixData(Data):
data: dict[ReadoutMitigationMatrixId, float] = field(default_factory=dict)
"""Raw data acquited."""

def add(self, qubits: list[QubitId], state: str, freqs: dict[str, int]):
"""Adding frequency to data."""

for result_state, freq in freqs.items():
self.data[
qubits
+ (
state,
result_state,
)
] = freq

for basis in [format(i, f"0{len(qubits)}b") for i in range(2 ** len(qubits))]:
if (
qubits
+ (
state,
basis,
)
not in self.data
):
self.data[
qubits
+ (
state,
basis,
)
] = 0

def matrix(self, qubits: list[QubitId]):
"""Retrieve data for single qubits list."""

matrix = np.zeros((2 ** len(qubits), 2 ** len(qubits)))
for state in computational_basis(len(qubits)):
column = np.zeros(2 ** len(qubits))
qubit_state_data = {
index: value
for index, value in self.data.items()
if index[-2] == state and qubits == list(index[: len(index) - 2])
}
for index, value in qubit_state_data.items():
column[(int(index[-1], 2))] = value / self.nshots
matrix[:, int(state, 2)] = np.flip(column)
return matrix


def _acquisition(
params: ReadoutMitigationMatrixParameters,
Expand All @@ -121,52 +75,54 @@ def _acquisition(

for qubits in targets:
nqubits = len(qubits)
for state in computational_basis(nqubits):
if params.pulses:
sequence = PulseSequence()
ro_pulses = {}
for q, bit in enumerate(state):
natives = platform.natives.single_qubit[qubits[q]]
if bit == "1":
sequence |= natives.RX()
sequence |= natives.MZ()
ro_pulses[qubits[q]] = list(
sequence.channel(platform.qubits[qubits[q]].acquisition)
)[-1]
results = platform.execute([sequence], nshots=params.nshots)
data.add(
tuple(qubits), state, calculate_frequencies(results, ro_pulses)
)
else:
c = Circuit(len(qubits))
for q, bit in enumerate(state):
if bit == "1":
c.add(gates.X(q))
c.add(gates.M(*[i for i in range(len(state))]))
_, results = execute_transpiled_circuit(
c, qubits, backend, nshots=params.nshots, transpiler=transpiler
for i in range(2**nqubits):
state = format(i, f"0{nqubits}b")
c = Circuit(
nqubits,
)
for q, bit in enumerate(state):
if bit == "1":
c.add(gates.X(q))
c.add(gates.M(*range(nqubits)))
_, results = execute_transpiled_circuit(
c, qubits, backend, nshots=params.nshots, transpiler=transpiler
)
frequencies = np.zeros(2 ** len(qubits))
for i, freq in results.frequencies().items():
frequencies[int(i, 2)] = freq
for freq in frequencies:
data.register_qubit(
ReadoutMitigationMatrixType,
(tuple(qubits)),
dict(
state=np.array([int(state, 2)]),
frequency=freq,
),
)
data.add(tuple(qubits), state, dict(results.frequencies()))
return data


def _fit(data: ReadoutMitigationMatrixData) -> ReadoutMitigationMatrixResults:
"""Post processing for readout mitigation matrix protocol."""
readout_mitigation_matrix = {}
measurement_matrix = {}
for qubit in data.qubit_list:
matrix = data.matrix(qubit)
measurement_matrix[tuple(qubit)] = matrix.tolist()
for qubits in data.qubit_list:
qubit_data = data.data[tuple(qubits)]
mitigation_matrix = []
for state in range(2 ** len(qubits)):
mitigation_matrix.append(qubit_data[qubit_data.state == state].frequency)
mitigation_matrix = np.vstack(mitigation_matrix) / data.nshots
try:
readout_mitigation_matrix[tuple(qubit)] = np.linalg.inv(matrix).tolist()
readout_mitigation_matrix[tuple(qubits)] = np.linalg.inv(
mitigation_matrix
).tolist()
except np.linalg.LinAlgError as e:
log.warning(f"ReadoutMitigationMatrix: the fitting was not succesful. {e}")

return ReadoutMitigationMatrixResults(
res = ReadoutMitigationMatrixResults(
readout_mitigation_matrix=readout_mitigation_matrix,
measurement_matrix=measurement_matrix,
)

return res


def _plot(
data: ReadoutMitigationMatrixData,
Expand All @@ -177,13 +133,15 @@ def _plot(
fitting_report = ""
figs = []
if fit is not None:
basis = computational_basis(len(target))
z = fit.measurement_matrix[tuple(target)]

computational_basis = [
format(i, f"0{len(target)}b") for i in range(2 ** len(target))
]
measurement_matrix = np.linalg.inv(fit.readout_mitigation_matrix[tuple(target)])
z = measurement_matrix
fig = px.imshow(
z,
x=basis,
y=basis[::-1],
x=computational_basis,
y=computational_basis,
text_auto=True,
labels={
"x": "Prepared States",
Expand Down
1 change: 1 addition & 0 deletions src/qibocal/protocols/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"""Confidence interval used to clean outliers."""
DELAY_FIT_PERCENTAGE = 10
"""Percentage of the first and last points used to fit the cable delay."""
STRING_TYPE = "<U100"


def int_to_binary(number: int, length: int) -> str:
Expand Down
10 changes: 1 addition & 9 deletions tests/runcards/protocols.yml
Original file line number Diff line number Diff line change
Expand Up @@ -777,19 +777,11 @@ actions:
native: CZ
parking: True

- id: readout_mitigation_matrix pulses
- id: readout_mitigation_matrix
operation: readout_mitigation_matrix
targets: [[0,1,2],[1,2]]
parameters:
nshots: 10
pulses: True

- id: readout_mitigation_matrix circuits
operation: readout_mitigation_matrix
targets: [[0,1,2],[1,2]]
parameters:
nshots: 10
pulses: False

- id: resonator_amplitude
operation: resonator_amplitude
Expand Down

0 comments on commit 07757c8

Please sign in to comment.