Skip to content

Commit 1ecda26

Browse files
Merge pull request #1038 from qiboteam/mermin_refactor
Mermin refactor
2 parents c8cd2a9 + 407d537 commit 1ecda26

File tree

11 files changed

+489
-156
lines changed

11 files changed

+489
-156
lines changed

src/qibocal/protocols/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
chsh_pulses,
7373
correct_virtual_z_phases,
7474
correct_virtual_z_phases_signal,
75+
mermin,
7576
optimize_two_qubit_gate,
7677
)
7778
from .two_qubit_state_tomography import two_qubit_state_tomography
@@ -149,5 +150,6 @@
149150
"standard_rb_2q",
150151
"standard_rb_2q_inter",
151152
"optimize_two_qubit_gate",
153+
"mermin",
152154
"ramsey_zz",
153155
]

src/qibocal/protocols/readout_mitigation_matrix.py

+44-103
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,18 @@
77
from qibo import gates
88
from qibo.backends import GlobalBackend
99
from qibo.models import Circuit
10-
from qibolab import ExecutionParameters
1110
from qibolab.platform import Platform
12-
from qibolab.pulses import PulseSequence
1311
from qibolab.qubits import QubitId
1412

1513
from qibocal.auto.operation import Data, Parameters, Results, Routine
1614
from qibocal.auto.transpile import dummy_transpiler, execute_transpiled_circuit
1715
from qibocal.config import log
1816

19-
from .utils import calculate_frequencies
20-
2117

2218
@dataclass
2319
class ReadoutMitigationMatrixParameters(Parameters):
2420
"""ReadoutMitigationMatrix matrix inputs."""
2521

26-
pulses: Optional[bool] = True
27-
"""Get readout mitigation matrix using pulses. If False gates will be used."""
2822
nshots: Optional[int] = None
2923
"""Number of shots."""
3024
relaxation_time: Optional[int] = None
@@ -37,10 +31,14 @@ class ReadoutMitigationMatrixResults(Results):
3731
field(default_factory=dict)
3832
)
3933
"""Readout mitigation matrices (inverse of measurement matrix)."""
40-
measurement_matrix: dict[tuple[QubitId, ...], npt.NDArray[np.float64]] = field(
41-
default_factory=dict
42-
)
43-
"""Matrix containing measurement matrices for each state."""
34+
35+
36+
ReadoutMitigationMatrixType = np.dtype(
37+
[
38+
("state", int),
39+
("frequency", np.float64),
40+
]
41+
)
4442

4543

4644
@dataclass
@@ -54,40 +52,6 @@ class ReadoutMitigationMatrixData(Data):
5452
data: dict = field(default_factory=dict)
5553
"""Raw data acquited."""
5654

57-
def add(self, qubits, state, freqs):
58-
for result_state, freq in freqs.items():
59-
self.data[
60-
qubits
61-
+ (
62-
state,
63-
result_state,
64-
)
65-
] = freq
66-
67-
for basis in [format(i, f"0{len(qubits)}b") for i in range(2 ** len(qubits))]:
68-
if (
69-
qubits
70-
+ (
71-
state,
72-
basis,
73-
)
74-
not in self.data
75-
):
76-
self.data[
77-
qubits
78-
+ (
79-
state,
80-
basis,
81-
)
82-
] = 0
83-
84-
def __getitem__(self, qubits):
85-
return {
86-
index: value
87-
for index, value in self.data.items()
88-
if qubits == list(index[: len(index) - 2])
89-
}
90-
9155

9256
def _acquisition(
9357
params: ReadoutMitigationMatrixParameters,
@@ -105,75 +69,52 @@ def _acquisition(
10569
nqubits = len(qubits)
10670
for i in range(2**nqubits):
10771
state = format(i, f"0{nqubits}b")
108-
if params.pulses:
109-
sequence = PulseSequence()
110-
for q, bit in enumerate(state):
111-
if bit == "1":
112-
sequence.add(
113-
platform.create_RX_pulse(
114-
qubits[q], start=0, relative_phase=0
115-
)
116-
)
117-
measurement_start = sequence.finish
118-
for q in range(len(state)):
119-
MZ_pulse = platform.create_MZ_pulse(
120-
qubits[q], start=measurement_start
121-
)
122-
sequence.add(MZ_pulse)
123-
results = platform.execute_pulse_sequence(
124-
sequence, ExecutionParameters(nshots=params.nshots)
125-
)
126-
data.add(
127-
tuple(qubits), state, calculate_frequencies(results, tuple(qubits))
72+
c = Circuit(
73+
nqubits,
74+
)
75+
for q, bit in enumerate(state):
76+
if bit == "1":
77+
c.add(gates.X(q))
78+
c.add(gates.M(*range(nqubits)))
79+
_, results = execute_transpiled_circuit(
80+
c, qubits, backend, nshots=params.nshots, transpiler=transpiler
81+
)
82+
frequencies = np.zeros(2 ** len(qubits))
83+
for i, freq in results.frequencies().items():
84+
frequencies[int(i, 2)] = freq
85+
for freq in frequencies:
86+
data.register_qubit(
87+
ReadoutMitigationMatrixType,
88+
(qubits),
89+
dict(
90+
state=np.array([int(state, 2)]),
91+
frequency=freq,
92+
),
12893
)
129-
else:
130-
c = Circuit(
131-
platform.nqubits,
132-
wire_names=[str(i) for i in range(platform.nqubits)],
133-
)
134-
for q, bit in enumerate(state):
135-
if bit == "1":
136-
c.add(gates.X(qubits[q]))
137-
c.add(gates.M(*[qubits[i] for i in range(len(state))]))
138-
_, results = execute_transpiled_circuit(
139-
c, qubit_map, backend, nshots=params.nshots, transpiler=transpiler
140-
)
141-
data.add(tuple(qubits), state, dict(results.frequencies()))
14294
return data
14395

14496

14597
def _fit(data: ReadoutMitigationMatrixData) -> ReadoutMitigationMatrixResults:
14698
"""Post processing for readout mitigation matrix protocol."""
14799
readout_mitigation_matrix = {}
148-
measurement_matrix = {}
149-
for qubit in data.qubit_list:
150-
qubit_data = data[qubit]
151-
matrix = np.zeros((2 ** len(qubit), 2 ** len(qubit)))
152-
computational_basis = [
153-
format(i, f"0{len(qubit)}b") for i in range(2 ** len(qubit))
154-
]
155-
for state in computational_basis:
156-
column = np.zeros(2 ** len(qubit))
157-
qubit_state_data = {
158-
index: value
159-
for index, value in qubit_data.items()
160-
if index[-2] == state
161-
}
162-
for index, value in qubit_state_data.items():
163-
column[(int(index[-1], 2))] = value / data.nshots
164-
matrix[:, int(state, 2)] = np.flip(column)
165-
166-
measurement_matrix[tuple(qubit)] = matrix.tolist()
100+
for qubits in data.qubit_list:
101+
qubit_data = data.data[tuple(qubits)]
102+
mitigation_matrix = []
103+
for state in range(2 ** len(qubits)):
104+
mitigation_matrix.append(qubit_data[qubit_data.state == state].frequency)
105+
mitigation_matrix = np.vstack(mitigation_matrix) / data.nshots
167106
try:
168-
readout_mitigation_matrix[tuple(qubit)] = np.linalg.inv(matrix).tolist()
107+
readout_mitigation_matrix[tuple(qubits)] = np.linalg.inv(
108+
mitigation_matrix
109+
).tolist()
169110
except np.linalg.LinAlgError as e:
170111
log.warning(f"ReadoutMitigationMatrix: the fitting was not succesful. {e}")
171-
172-
return ReadoutMitigationMatrixResults(
112+
res = ReadoutMitigationMatrixResults(
173113
readout_mitigation_matrix=readout_mitigation_matrix,
174-
measurement_matrix=measurement_matrix,
175114
)
176115

116+
return res
117+
177118

178119
def _plot(
179120
data: ReadoutMitigationMatrixData,
@@ -187,12 +128,12 @@ def _plot(
187128
computational_basis = [
188129
format(i, f"0{len(target)}b") for i in range(2 ** len(target))
189130
]
190-
z = fit.measurement_matrix[tuple(target)]
191-
131+
measurement_matrix = np.linalg.inv(fit.readout_mitigation_matrix[tuple(target)])
132+
z = measurement_matrix
192133
fig = px.imshow(
193134
z,
194135
x=computational_basis,
195-
y=computational_basis[::-1],
136+
y=computational_basis,
196137
text_auto=True,
197138
labels={
198139
"x": "Prepeared States",
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from .chevron import chevron, chevron_signal
22
from .chsh import chsh_circuits, chsh_pulses
3+
from .mermin import mermin
34
from .optimize import optimize_two_qubit_gate
45
from .virtual_z_phases import correct_virtual_z_phases
56
from .virtual_z_phases_signal import correct_virtual_z_phases_signal

src/qibocal/protocols/two_qubit_interaction/chsh/circuits.py

+27-30
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from .utils import READOUT_BASIS
88

99

10-
def create_bell_circuit(nqubits, qubits, theta=np.pi / 4, bell_state=0):
10+
def create_bell_circuit(theta=np.pi / 4, bell_state=0):
1111
"""Creates the circuit to generate the bell states and with a theta-measurement
1212
bell_state chooses the initial bell state for the test:
1313
0 -> |00>+|11>
@@ -17,24 +17,24 @@ def create_bell_circuit(nqubits, qubits, theta=np.pi / 4, bell_state=0):
1717
Native defaults to only using GPI2 and GPI gates.
1818
"""
1919
p = [0, 0]
20-
c = Circuit(nqubits)
21-
c.add(gates.H(qubits[0]))
22-
c.add(gates.H(qubits[1]))
23-
c.add(gates.CZ(qubits[0], qubits[1]))
24-
c.add(gates.H(qubits[1]))
20+
c = Circuit(2)
21+
c.add(gates.H(0))
22+
c.add(gates.H(1))
23+
c.add(gates.CZ(0, 1))
24+
c.add(gates.H(1))
2525
if bell_state == 1:
26-
c.add(gates.Z(qubits[0]))
26+
c.add(gates.Z(0))
2727
elif bell_state == 2:
28-
c.add(gates.Z(qubits[0]))
29-
c.add(gates.X(qubits[0]))
28+
c.add(gates.Z(0))
29+
c.add(gates.X(0))
3030
elif bell_state == 3:
31-
c.add(gates.X(qubits[0]))
31+
c.add(gates.X(0))
3232

33-
c.add(gates.RY(qubits[0], theta))
33+
c.add(gates.RY(0, theta))
3434
return c, p
3535

3636

37-
def create_bell_circuit_native(nqubits, qubits, theta=np.pi / 4, bell_state=0):
37+
def create_bell_circuit_native(theta=np.pi / 4, bell_state=0):
3838
"""Creates the circuit to generate the bell states and with a theta-measurement
3939
bell_state chooses the initial bell state for the test:
4040
0 -> |00>+|11>
@@ -44,35 +44,33 @@ def create_bell_circuit_native(nqubits, qubits, theta=np.pi / 4, bell_state=0):
4444
Native defaults to only using GPI2 and GPI gates.
4545
"""
4646

47-
c = Circuit(nqubits)
47+
c = Circuit(2)
4848
p = [0, 0]
49-
c.add(gates.GPI2(qubits[0], np.pi / 2))
50-
c.add(gates.GPI2(qubits[1], np.pi / 2))
51-
c.add(gates.CZ(qubits[0], qubits[1]))
52-
c.add(gates.GPI2(qubits[1], -np.pi / 2))
49+
c.add(gates.GPI2(0, np.pi / 2))
50+
c.add(gates.GPI2(1, np.pi / 2))
51+
c.add(gates.CZ(0, 1))
52+
c.add(gates.GPI2(1, -np.pi / 2))
5353
if bell_state == 0:
5454
p[0] += np.pi
5555
elif bell_state == 1:
5656
p[0] += 0
5757
elif bell_state == 2:
5858
p[0] += 0
59-
c.add(gates.GPI2(qubits[0], p[0]))
60-
c.add(gates.GPI2(qubits[0], p[0]))
59+
c.add(gates.GPI2(0, p[0]))
60+
c.add(gates.GPI2(0, p[0]))
6161
elif bell_state == 3:
6262
p[0] += np.pi
63-
c.add(gates.GPI2(qubits[0], p[0]))
64-
c.add(gates.GPI2(qubits[0], p[0]))
63+
c.add(gates.GPI2(0, p[0]))
64+
c.add(gates.GPI2(0, p[0]))
6565

66-
c.add(gates.GPI2(qubits[0], p[0]))
66+
c.add(gates.GPI2(0, p[0]))
6767
p[0] += theta
68-
c.add(gates.GPI2(qubits[0], p[0] + np.pi))
68+
c.add(gates.GPI2(0, p[0] + np.pi))
6969

7070
return c, p
7171

7272

7373
def create_chsh_circuits(
74-
platform,
75-
qubits,
7674
theta=np.pi / 4,
7775
bell_state=0,
7876
native=True,
@@ -84,15 +82,14 @@ def create_chsh_circuits(
8482
"""
8583
create_bell = create_bell_circuit_native if native else create_bell_circuit
8684
chsh_circuits = {}
87-
nqubits = platform.nqubits if platform else max(qubits) + 1
8885
for basis in readout_basis:
89-
c, p = create_bell(nqubits, qubits, theta, bell_state)
86+
c, p = create_bell(theta, bell_state)
9087
for i, base in enumerate(basis):
9188
if base == "X":
9289
if native:
93-
c.add(gates.GPI2(qubits[i], p[i] + np.pi / 2))
90+
c.add(gates.GPI2(i, p[i] + np.pi / 2))
9491
else:
95-
c.add(gates.H(qubits[i]))
96-
c.add(gates.M(*qubits))
92+
c.add(gates.H(i))
93+
c.add(gates.M(0, 1))
9794
chsh_circuits[basis] = c
9895
return chsh_circuits

0 commit comments

Comments
 (0)