Skip to content

Commit 08dcd54

Browse files
andrehchewshanks
andauthored
Update layer_fidelity_analysis.py to have benchmark suffix (#1583)
Co-authored-by: Will Shanks <[email protected]>
1 parent f321b6c commit 08dcd54

File tree

4 files changed

+89
-15
lines changed

4 files changed

+89
-15
lines changed

qiskit_experiments/library/randomized_benchmarking/layer_fidelity.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ def __init__(
139139
one_qubit_basis_gates: Optional[Sequence[str]] = None,
140140
layer_barrier: Optional[bool] = True,
141141
min_delay: Optional[Sequence[int]] = None,
142+
benchmark_suffix: Optional[str] = "",
142143
):
143144
"""Initialize a layer fidelity experiment.
144145
@@ -172,6 +173,9 @@ def __init__(
172173
this options requires at least one 1Q edge (a qubit in physical_qubits but
173174
not in two_qubit_layers) to be applied. Also will not have an impact on the 2Q gates
174175
if layer_barrier=False.
176+
benchmark_suffix (str): Optional. Suffix string to be appended to the end of the names of the
177+
associated analysis results. Intended to allow for easier bookeeping if multiple types of
178+
gates are being tracked.
175179
176180
Raises:
177181
QiskitError: If any invalid argument is supplied.
@@ -192,6 +196,8 @@ def __init__(
192196
super().__init__(
193197
physical_qubits, analysis=LayerFidelityAnalysis(full_layers), backend=backend
194198
)
199+
200+
self.analysis.benchmark_suffix = benchmark_suffix
195201
# assert isinstance(backend, BackendV2)
196202

197203
# Verify parameters

qiskit_experiments/library/randomized_benchmarking/layer_fidelity_analysis.py

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class _ProcessFidelityAnalysis(curve.CurveAnalysis):
6060
.. ref_arxiv:: 1 2311.05933
6161
"""
6262

63-
def __init__(self, physical_qubits):
63+
def __init__(self, physical_qubits, benchmark_suffix=""):
6464
super().__init__(
6565
models=[
6666
lmfit.models.ExpressionModel(
@@ -77,6 +77,17 @@ def __init__(self, physical_qubits):
7777
self.plotter.set_figure_options(
7878
figure_title=f"Simultaneous Direct RB on Qubit{physical_qubits}",
7979
)
80+
self._benchmark_suffix = benchmark_suffix
81+
82+
@property
83+
def benchmark_suffix(self):
84+
"""Getter function for benchmark suffix parameter."""
85+
return self._benchmark_suffix
86+
87+
@benchmark_suffix.setter
88+
def benchmark_suffix(self, value):
89+
"""Setter function for benchmark suffix parameter."""
90+
self._benchmark_suffix = value
8091

8192
@classmethod
8293
def _default_options(cls):
@@ -157,7 +168,7 @@ def _create_analysis_results(
157168
metadata.update(fit_data.params)
158169
outcomes.append(
159170
AnalysisResultData(
160-
name="ProcessFidelity",
171+
name="ProcessFidelity" + self.benchmark_suffix,
161172
value=pf,
162173
chisq=fit_data.reduced_chisq,
163174
quality=quality,
@@ -166,7 +177,7 @@ def _create_analysis_results(
166177
)
167178
outcomes.append(
168179
AnalysisResultData(
169-
name="EPL",
180+
name="EPL" + self.benchmark_suffix,
170181
value=epl,
171182
chisq=fit_data.reduced_chisq,
172183
quality=quality,
@@ -188,7 +199,7 @@ def _run_analysis(
188199
traceback.format_exc(),
189200
)
190201
failed_result = AnalysisResultData(
191-
name="ProcessFidelity",
202+
name="ProcessFidelity" + self.benchmark_suffix,
192203
value=None,
193204
quality="bad",
194205
extra={"qubits": self._physical_qubits, "reason": "analysis_failure"},
@@ -234,15 +245,36 @@ def _evaluate_quality_with_reason(
234245
class _SingleLayerFidelityAnalysis(CompositeAnalysis):
235246
"""A class to estimate a process fidelity per disjoint layer."""
236247

237-
def __init__(self, layer, analyses=None):
248+
def __init__(self, layer, analyses=None, benchmark_suffix=""):
238249
if analyses:
239250
if len(layer) != len(analyses):
240251
raise AnalysisError("'analyses' must have the same length with 'layer'")
241252
else:
242-
analyses = [_ProcessFidelityAnalysis(qubits) for qubits in layer]
253+
analyses = [
254+
_ProcessFidelityAnalysis(qubits, benchmark_suffix=benchmark_suffix)
255+
for qubits in layer
256+
]
243257

244258
super().__init__(analyses, flatten_results=True)
245259
self._layer = layer
260+
self._benchmark_suffix = benchmark_suffix
261+
self._set_benchmark_suffix_on_subanalyses(benchmark_suffix)
262+
263+
@property
264+
def benchmark_suffix(self):
265+
"""Getter function for benchmark suffix parameter."""
266+
return self._benchmark_suffix
267+
268+
@benchmark_suffix.setter
269+
def benchmark_suffix(self, value):
270+
"""Setter function for benchmark suffix parameter."""
271+
self._benchmark_suffix = value
272+
self._set_benchmark_suffix_on_subanalyses(value)
273+
274+
def _set_benchmark_suffix_on_subanalyses(self, value):
275+
for subanalysis in self._analyses:
276+
if hasattr(subanalysis, "benchmark_suffix"):
277+
subanalysis.benchmark_suffix = value
246278

247279
def _run_analysis(
248280
self, experiment_data: ExperimentData
@@ -251,12 +283,16 @@ def _run_analysis(
251283
# Run composite analysis and extract sub-experiments results
252284
analysis_results, figures = super()._run_analysis(experiment_data)
253285
# Calculate single layer fidelity from process fidelities of subsystems
254-
pf_results = [res for res in analysis_results if res.name == "ProcessFidelity"]
286+
pf_results = [
287+
res
288+
for res in analysis_results
289+
if res.name == "ProcessFidelity" + self.benchmark_suffix
290+
]
255291
pfs = [res.value for res in pf_results]
256292
slf = np.prod(pfs)
257293
quality_slf = "good" if all(sub.quality == "good" for sub in pf_results) else "bad"
258294
slf_result = AnalysisResultData(
259-
name="SingleLF",
295+
name="SingleLF" + self.benchmark_suffix,
260296
value=slf,
261297
quality=quality_slf,
262298
extra={"qubits": [q for qubits in self._layer for q in qubits]},
@@ -267,7 +303,7 @@ def _run_analysis(
267303
except Exception: # pylint: disable=broad-except
268304
LOG.error("%s failed: %s", self.__class__.__name__, traceback.format_exc())
269305
failed_result = AnalysisResultData(
270-
name="SingleLF",
306+
name="SingleLF" + self.benchmark_suffix,
271307
value=None,
272308
quality="bad",
273309
extra={
@@ -295,7 +331,7 @@ class LayerFidelityAnalysis(CompositeAnalysis):
295331
.. ref_arxiv:: 1 2311.05933
296332
"""
297333

298-
def __init__(self, layers, analyses=None):
334+
def __init__(self, layers, analyses=None, benchmark_suffix=""):
299335
if analyses:
300336
if len(layers) != len(analyses):
301337
raise AnalysisError("'analyses' must have the same length with 'layers'")
@@ -305,6 +341,23 @@ def __init__(self, layers, analyses=None):
305341
super().__init__(analyses, flatten_results=True)
306342
self.num_layers = len(layers)
307343
self.num_2q_gates = sum(1 if len(qs) == 2 else 0 for lay in layers for qs in lay)
344+
self._benchmark_suffix = benchmark_suffix
345+
346+
@property
347+
def benchmark_suffix(self):
348+
"""Getter function for benchmark suffix parameter."""
349+
return self._benchmark_suffix
350+
351+
@benchmark_suffix.setter
352+
def benchmark_suffix(self, value):
353+
"""Setter function for benchmark suffix parameter."""
354+
self._benchmark_suffix = value
355+
self._set_benchmark_suffix_on_subanalyses(value)
356+
357+
def _set_benchmark_suffix_on_subanalyses(self, value):
358+
for subanalysis in self._analyses:
359+
if hasattr(subanalysis, "benchmark_suffix"):
360+
subanalysis.benchmark_suffix = value
308361

309362
def _run_analysis(
310363
self, experiment_data: ExperimentData
@@ -328,18 +381,20 @@ def _run_analysis(
328381
# Run composite analysis and extract sub-experiments results
329382
analysis_results, figures = super()._run_analysis(experiment_data)
330383
# Calculate full layer fidelity from single layer fidelities
331-
slf_results = [res for res in analysis_results if res.name == "SingleLF"]
384+
slf_results = [
385+
res for res in analysis_results if res.name == "SingleLF" + self.benchmark_suffix
386+
]
332387
slfs = [res.value for res in slf_results]
333388
lf = np.prod(slfs)
334389
quality_lf = "good" if all(sub.quality == "good" for sub in slf_results) else "bad"
335390
lf_result = AnalysisResultData(
336-
name="LF",
391+
name="LF" + self.benchmark_suffix,
337392
value=lf,
338393
quality=quality_lf,
339394
)
340395
eplg = 1 - (lf ** (1 / self.num_2q_gates))
341396
eplg_result = AnalysisResultData(
342-
name="EPLG",
397+
name="EPLG" + self.benchmark_suffix,
343398
value=eplg,
344399
quality=quality_lf,
345400
)
@@ -350,13 +405,13 @@ def _run_analysis(
350405
LOG.error("%s failed: %s", self.__class__.__name__, traceback.format_exc())
351406
failed_results = [
352407
AnalysisResultData(
353-
name="LF",
408+
name="LF" + self.benchmark_suffix,
354409
value=None,
355410
quality="bad",
356411
extra={"reason": "analysis_failure"},
357412
),
358413
AnalysisResultData(
359-
name="EPLG",
414+
name="EPLG" + self.benchmark_suffix,
360415
value=None,
361416
quality="bad",
362417
extra={"reason": "analysis_failure"},

qiskit_experiments/library/randomized_benchmarking/layer_fidelity_unitary.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ def __init__(
135135
one_qubit_basis_gates: Optional[Sequence[str]] = None,
136136
layer_barrier: Optional[bool] = True,
137137
min_delay: Optional[Sequence[int]] = None,
138+
benchmark_suffix: Optional[str] = "",
138139
):
139140
"""Initialize a unitary layer fidelity experiment.
140141
@@ -170,6 +171,9 @@ def __init__(
170171
this options requires at least one 1Q edge (a qubit in physical_qubits but
171172
not in two_qubit_layers) to be applied. Also will not have an impact on the 2Q gates
172173
if layer_barrier=False.
174+
benchmark_suffix (str): Optional. Suffix string to be appended to the end of the names of the
175+
associated analysis results. Intended to allow for easier bookeeping if multiple types of
176+
gates are being tracked.
173177
174178
Raises:
175179
QiskitError: If any invalid argument is supplied.
@@ -190,6 +194,8 @@ def __init__(
190194
super().__init__(
191195
physical_qubits, analysis=LayerFidelityAnalysis(full_layers), backend=backend
192196
)
197+
198+
self.analysis.benchmark_suffix = benchmark_suffix
193199
# assert isinstance(backend, BackendV2)
194200

195201
# Verify parameters
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
features:
3+
- |
4+
A new ``benchmark_suffix`` argument for the :class:`~.LayerFidelity`
5+
and :class:`~.LayerFidelityUnitary` classes has been added which enables
6+
users to append a descriptive suffix to the names of the analysis results in
7+
these experiments, which makes bookkeeping for different types of gates easier.

0 commit comments

Comments
 (0)