Skip to content

Commit d8e8dda

Browse files
Merge pull request #1076 from qiboteam/fix_backend
Handling global backend for protocols involving circuits
2 parents 5cfeb8c + d519948 commit d8e8dda

16 files changed

+70
-240
lines changed

src/qibocal/auto/execute.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,7 @@ def create(cls, name: str, platform: Union[Platform, str, None] = None):
104104
platform = (
105105
platform
106106
if isinstance(platform, Platform)
107-
else create_platform(
108-
platform
109-
if platform is not None
110-
else os.environ.get("QIBO_PLATFORM", "dummy")
111-
)
107+
else create_platform(platform if platform is not None else "dummy")
112108
)
113109
return cls(
114110
name=name,

src/qibocal/auto/runcard.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""Specify runcard layout, handles (de)serialization."""
22

3-
import os
43
from dataclasses import asdict
54
from pathlib import Path
65
from typing import Any, Optional, Union
@@ -33,7 +32,7 @@ class Runcard:
3332
"""
3433
backend: str = "qibolab"
3534
"""Qibo backend."""
36-
platform: str = os.environ.get("QIBO_PLATFORM", "dummy")
35+
platform: str = "dummy"
3736
"""Qibolab platform."""
3837
update: bool = True
3938

src/qibocal/auto/transpile.py

+13-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import Optional
22

33
from qibo import Circuit
4-
from qibo.backends.abstract import Backend
4+
from qibo.backends import Backend
55
from qibo.transpiler.pipeline import Passes
66
from qibo.transpiler.unroller import NativeGates, Unroller
77
from qibolab.qubits import QubitId
@@ -28,20 +28,18 @@ def transpile_circuits(
2828
are all string or all integers.
2929
"""
3030
transpiled_circuits = []
31-
32-
qubits = list(backend.platform.qubits)
31+
platform = backend.platform
32+
qubits = list(platform.qubits)
3333
if isinstance(qubit_maps[0][0], str):
3434
for i, qubit_map in enumerate(qubit_maps):
3535
qubit_map = map(lambda x: qubits.index(x), qubit_map)
3636
qubit_maps[i] = list(qubit_map)
37-
if backend.name == "qibolab":
38-
platform_nqubits = backend.platform.nqubits
39-
for circuit, qubit_map in zip(circuits, qubit_maps):
40-
new_circuit = pad_circuit(platform_nqubits, circuit, qubit_map)
41-
transpiled_circ, _ = transpiler(new_circuit)
42-
transpiled_circuits.append(transpiled_circ)
43-
else:
44-
transpiled_circuits = circuits
37+
platform_nqubits = platform.nqubits
38+
for circuit, qubit_map in zip(circuits, qubit_maps):
39+
new_circuit = pad_circuit(platform_nqubits, circuit, qubit_map)
40+
transpiled_circ, _ = transpiler(new_circuit)
41+
transpiled_circuits.append(transpiled_circ)
42+
4543
return transpiled_circuits
4644

4745

@@ -99,20 +97,19 @@ def execute_transpiled_circuit(
9997
backend,
10098
transpiler,
10199
)[0]
100+
102101
return transpiled_circ, backend.execute_circuit(
103102
transpiled_circ, initial_state=initial_state, nshots=nshots
104103
)
105104

106105

107-
def dummy_transpiler(backend) -> Optional[Passes]:
106+
def dummy_transpiler(backend: Backend) -> Passes:
108107
"""
109108
If the backend is `qibolab`, a transpiler with just an unroller is returned,
110109
otherwise None.
111110
"""
112-
if backend.name == "qibolab":
113-
unroller = Unroller(NativeGates.default())
114-
return Passes(connectivity=backend.platform.topology, passes=[unroller])
115-
return None
111+
unroller = Unroller(NativeGates.default())
112+
return Passes(connectivity=backend.platform.topology, passes=[unroller])
116113

117114

118115
def pad_circuit(nqubits, circuit: Circuit, qubit_map: list[int]) -> Circuit:

src/qibocal/protocols/randomized_benchmarking/noisemodels.py

-52
This file was deleted.

src/qibocal/protocols/randomized_benchmarking/standard_rb.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from dataclasses import dataclass, field
1+
from dataclasses import dataclass
22
from typing import Iterable, Optional, TypedDict, Union
33

44
import numpy as np
@@ -52,12 +52,6 @@ class StandardRBParameters(Parameters):
5252
If ``None``, uses a random seed.
5353
Defaults is ``None``.
5454
"""
55-
noise_model: Optional[str] = None
56-
"""For simulation purposes, string has to match what is in
57-
:mod:`qibocal.protocols.randomized_benchmarking.noisemodels`"""
58-
noise_params: Optional[list] = field(default_factory=list)
59-
"""With this the noise model will be initialized, if not given random
60-
values will be used."""
6155
nshots: int = 10
6256
"""Just to add the default value."""
6357

src/qibocal/protocols/randomized_benchmarking/utils.py

+12-34
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
import numpy as np
88
import numpy.typing as npt
99
from qibo import gates
10-
from qibo.backends import get_backend
11-
from qibo.config import raise_error
10+
from qibo.backends import construct_backend
1211
from qibo.models import Circuit
1312
from qibolab.platform import Platform
1413
from qibolab.qubits import QubitId, QubitPairId
@@ -19,8 +18,6 @@
1918
execute_transpiled_circuit,
2019
execute_transpiled_circuits,
2120
)
22-
from qibocal.config import raise_error
23-
from qibocal.protocols.randomized_benchmarking import noisemodels
2421
from qibocal.protocols.randomized_benchmarking.dict_utils import (
2522
SINGLE_QUBIT_CLIFFORDS_NAMES,
2623
calculate_pulses_clifford,
@@ -118,7 +115,6 @@ def random_circuits(
118115
targets: list[Union[QubitId, QubitPairId]],
119116
niter,
120117
rb_gen,
121-
noise_model=None,
122118
inverse_layer=True,
123119
single_qubit=True,
124120
file_inv=pathlib.Path(),
@@ -134,8 +130,6 @@ def random_circuits(
134130
if inverse_layer:
135131
add_inverse_layer(circuit, rb_gen, single_qubit, file_inv)
136132
add_measurement_layer(circuit)
137-
if noise_model is not None:
138-
circuit = noise_model.apply(circuit)
139133
circuits.append(circuit)
140134
indexes[target].append(random_index)
141135

@@ -341,30 +335,17 @@ def setup(
341335
interleave: Optional[str] = None,
342336
):
343337
"""
344-
Set up the randomized benchmarking experiment backend, noise model and data class.
338+
Set up the randomized benchmarking experiment backend and data class.
345339
346340
Args:
347341
params (Parameters): The parameters for the experiment.
348342
single_qubit (bool, optional): Flag indicating whether the experiment is for a single qubit or two qubits. Defaults to True.
349343
interleave: (str, optional): The type of interleaving to apply. Defaults to None.
350344
351345
Returns:
352-
tuple: A tuple containing the experiment data, noise model, and backend.
346+
tuple: A tuple containing the experiment data and backend.
353347
"""
354-
355-
backend = get_backend()
356-
backend.platform = platform
357-
# For simulations, a noise model can be added.
358-
noise_model = None
359-
if params.noise_model is not None:
360-
if backend.name == "qibolab":
361-
raise_error(
362-
ValueError,
363-
"Backend qibolab (%s) does not perform noise models simulation. ",
364-
)
365-
366-
noise_model = getattr(noisemodels, params.noise_model)(params.noise_params)
367-
params.noise_params = noise_model.params.tolist()
348+
backend = construct_backend(backend="qibolab", platform=platform)
368349
# Set up the scan (here an iterator of circuits of random clifford gates with an inverse).
369350
if single_qubit:
370351
cls = RBData
@@ -380,12 +361,10 @@ def setup(
380361
niter=params.niter,
381362
)
382363

383-
return data, noise_model, backend
364+
return data, backend
384365

385366

386-
def get_circuits(
387-
params, targets, add_inverse_layer, interleave, noise_model, single_qubit=True
388-
):
367+
def get_circuits(params, targets, add_inverse_layer, interleave, single_qubit=True):
389368
"""
390369
Generate randomized benchmarking circuits.
391370
@@ -394,7 +373,6 @@ def get_circuits(
394373
targets (list): List of target qubit IDs.
395374
add_inverse_layer (bool): Flag indicating whether to add an inverse layer to the circuits.
396375
interleave (str): String indicating whether to interleave the circuits with the given gate.
397-
noise_model (str): Noise model string.
398376
single_qubit (bool, optional): Flag indicating whether to generate single qubit circuits.
399377
400378
Returns:
@@ -421,7 +399,6 @@ def get_circuits(
421399
qubits_ids,
422400
params.niter,
423401
rb_gen,
424-
noise_model,
425402
add_inverse_layer,
426403
single_qubit,
427404
inv_file,
@@ -455,6 +432,7 @@ def execute_circuits(circuits, targets, params, backend, single_qubit=True):
455432
456433
"""
457434
# Execute the circuits
435+
platform = backend.platform
458436
transpiler = dummy_transpiler(backend)
459437
qubit_maps = (
460438
[[i] for i in targets] * (len(params.depths) * params.niter)
@@ -503,9 +481,9 @@ def rb_acquisition(
503481
Returns:
504482
RBData: The depths, samples, and ground state probability of each experiment in the scan.
505483
"""
506-
data, noise_model, backend = setup(params, platform, single_qubit=True)
484+
data, backend = setup(params, platform, single_qubit=True)
507485
circuits, indexes, npulses_per_clifford = get_circuits(
508-
params, targets, add_inverse_layer, interleave, noise_model, single_qubit=True
486+
params, targets, add_inverse_layer, interleave, single_qubit=True
509487
)
510488
executed_circuits = execute_circuits(circuits, targets, params, backend)
511489

@@ -549,10 +527,10 @@ def twoq_rb_acquisition(
549527
Returns:
550528
RB2QData: The acquired data for two qubit randomized benchmarking.
551529
"""
552-
553-
data, noise_model, backend = setup(params, platform, single_qubit=False)
530+
targets = [tuple(pair) if isinstance(pair, list) else pair for pair in targets]
531+
data, backend = setup(params, platform, single_qubit=False)
554532
circuits, indexes, npulses_per_clifford = get_circuits(
555-
params, targets, add_inverse_layer, interleave, noise_model, single_qubit=False
533+
params, targets, add_inverse_layer, interleave, single_qubit=False
556534
)
557535
executed_circuits = execute_circuits(
558536
circuits, targets, params, backend, single_qubit=False

src/qibocal/protocols/readout_mitigation_matrix.py

+26-22
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import numpy.typing as npt
66
import plotly.express as px
77
from qibo import gates
8-
from qibo.backends import get_backend
8+
from qibo.backends import construct_backend
99
from qibo.models import Circuit
1010
from qibolab.platform import Platform
1111
from qibolab.qubits import QubitId
@@ -61,8 +61,7 @@ def _acquisition(
6161
data = ReadoutMitigationMatrixData(
6262
nshots=params.nshots, qubit_list=[list(qq) for qq in targets]
6363
)
64-
backend = get_backend()
65-
backend.platform = platform
64+
backend = construct_backend("qibolab", platform=platform)
6665
transpiler = dummy_transpiler(backend)
6766
qubit_map = [i for i in range(platform.nqubits)]
6867
for qubits in targets:
@@ -125,25 +124,30 @@ def _plot(
125124
fitting_report = ""
126125
figs = []
127126
if fit is not None:
128-
computational_basis = [
129-
format(i, f"0{len(target)}b") for i in range(2 ** len(target))
130-
]
131-
measurement_matrix = np.linalg.inv(fit.readout_mitigation_matrix[tuple(target)])
132-
z = measurement_matrix
133-
fig = px.imshow(
134-
z,
135-
x=computational_basis,
136-
y=computational_basis,
137-
text_auto=True,
138-
labels={
139-
"x": "Prepeared States",
140-
"y": "Measured States",
141-
"color": "Probabilities",
142-
},
143-
width=700,
144-
height=700,
145-
)
146-
figs.append(fig)
127+
if tuple(target) in fit.readout_mitigation_matrix:
128+
computational_basis = [
129+
format(i, f"0{len(target)}b") for i in range(2 ** len(target))
130+
]
131+
# use pinv since it should be already invertibile
132+
# however when casting to list we could lose precision
133+
measurement_matrix = np.linalg.pinv(
134+
fit.readout_mitigation_matrix[tuple(target)]
135+
)
136+
z = measurement_matrix
137+
fig = px.imshow(
138+
z,
139+
x=computational_basis,
140+
y=computational_basis,
141+
text_auto=True,
142+
labels={
143+
"x": "Prepeared States",
144+
"y": "Measured States",
145+
"color": "Probabilities",
146+
},
147+
width=700,
148+
height=700,
149+
)
150+
figs.append(fig)
147151
return figs, fitting_report
148152

149153

src/qibocal/protocols/state_tomography.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import plotly.graph_objects as go
99
from plotly.subplots import make_subplots
1010
from qibo import Circuit, gates
11-
from qibo.backends import NumpyBackend, get_backend, matrices
11+
from qibo.backends import NumpyBackend, construct_backend, matrices
1212
from qibo.quantum_info import fidelity, partial_trace
1313
from qibolab.platform import Platform
1414
from qibolab.qubits import QubitId
@@ -102,8 +102,7 @@ def _acquisition(
102102
if params.circuit is None:
103103
params.circuit = Circuit(len(targets))
104104

105-
backend = get_backend()
106-
backend.platform = platform
105+
backend = construct_backend("qibolab", platform=platform)
107106
transpiler = dummy_transpiler(backend)
108107

109108
data = StateTomographyData(

0 commit comments

Comments
 (0)