From 32f6675fc742dfd4748caf02306f1c12611f074a Mon Sep 17 00:00:00 2001 From: Dean Poulos Date: Fri, 7 Feb 2025 00:46:56 +1100 Subject: [PATCH 01/11] Bump version to 0.19.0 --- CHANGELOG.md | 5 ++++- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 890af748..02adee88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## [Unreleased] + +## [0.18.3] - 2025-02-07 ### Added - characterization/two_qubit_rb - Migrate standard two-qubit randomized benchmarking implementation. @@ -406,7 +408,8 @@ operation (readout pulse for instance) already defined in the configuration. ### Added - This release exposes the baking, RB and XEB functionality. -[Unreleased]: https://github.com/qua-platform/py-qua-tools/compare/v0.18.2...HEAD +[Unreleased]: https://github.com/qua-platform/py-qua-tools/compare/v0.19.0...HEAD +[0.19.0]: https://github.com/qua-platform/py-qua-tools/compare/v0.18.2...v0.19.0 [0.18.2]: https://github.com/qua-platform/py-qua-tools/compare/v0.18.1...v0.18.2 [0.18.1]: https://github.com/qua-platform/py-qua-tools/compare/v0.18.0...v0.18.1 [0.18.0]: https://github.com/qua-platform/py-qua-tools/compare/v0.17.7...v0.18.0 diff --git a/pyproject.toml b/pyproject.toml index ca33ac67..0d2fb288 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "qualang-tools" -version = "v0.18.2" +version = "v0.19.0" description = "The qualang_tools package includes various tools related to QUA programs in Python" authors = ["Quantum Machines "] license = "BSD-3-Clause" From 16e5e97316c488a268287bf2bca7a56764f87917 Mon Sep 17 00:00:00 2001 From: Dean Poulos Date: Fri, 7 Feb 2025 00:47:23 +1100 Subject: [PATCH 02/11] Bump version to 0.19.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02adee88..c32581dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## [Unreleased] -## [0.18.3] - 2025-02-07 +## [0.19.0] - 2025-02-07 ### Added - characterization/two_qubit_rb - Migrate standard two-qubit randomized benchmarking implementation. From 556d771ef3baf51b76120c594e05f34bfe948a7b Mon Sep 17 00:00:00 2001 From: Dean Poulos Date: Fri, 7 Feb 2025 04:54:07 +1100 Subject: [PATCH 03/11] Switch circuit-depth and repeat axes, as well as overhaul plotting. --- .../characterization/two_qubit_rb/__init__.py | 3 +- .../two_qubit_rb/two_qubit_rb/RBResult.py | 72 +++++++++++++++---- .../two_qubit_rb/two_qubit_rb/TwoQubitRB.py | 21 ++++-- .../two_qubit_rb/two_qubit_rb_example.py | 3 + 4 files changed, 79 insertions(+), 20 deletions(-) diff --git a/qualang_tools/characterization/two_qubit_rb/__init__.py b/qualang_tools/characterization/two_qubit_rb/__init__.py index 7519e6cd..64ea176b 100644 --- a/qualang_tools/characterization/two_qubit_rb/__init__.py +++ b/qualang_tools/characterization/two_qubit_rb/__init__.py @@ -1,3 +1,4 @@ from .two_qubit_rb import * +from .two_qubit_rb.RBResult import RBResult -__all__ = ["TwoQubitRb", "TwoQubitRbDebugger"] +__all__ = ["TwoQubitRb", "TwoQubitRbDebugger", "RBResult"] diff --git a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py index 811f5668..212a4b1c 100644 --- a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py +++ b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py @@ -27,10 +27,10 @@ def __post_init__(self): Initializes the xarray Dataset to store the RB experiment data. """ self.data = xr.Dataset( - data_vars={"state": (["circuit_depth", "repeat", "average"], self.state)}, + data_vars={"state": (["repeat", "circuit_depth", "average"], self.state)}, coords={ - "circuit_depth": self.circuit_depths, "repeat": range(self.num_repeats), + "circuit_depth": self.circuit_depths, "average": range(self.num_averages), }, ) @@ -64,25 +64,73 @@ def plot(self): def plot_with_fidelity(self): """ Plots the RB fidelity as a function of circuit depth, including a fit to an exponential decay model. - The fitted curve is overlaid with the raw data points. + The fitted curve is overlaid with the raw data points, and error bars are included. """ A, alpha, B = self.fit_exponential() fidelity = self.get_fidelity(alpha) + # Compute error bars + error_bars = (self.data == 0).mean(dim="average").std(dim="repeat").state.data + plt.figure() - plt.plot(self.circuit_depths, self.get_decay_curve(), "o", label="Data") - plt.plot( + plt.errorbar( self.circuit_depths, - rb_decay_curve(np.array(self.circuit_depths), A, alpha, B), - "-", - label=f"Fidelity={fidelity * 100:.3f}%\nalpha={alpha:.4f}", + self.get_decay_curve(), + yerr=error_bars, + fmt=".", + capsize=2, + elinewidth=0.5, + color='blue', + label="Experimental Data", + ) + + circuit_depths_smooth_axis = np.linspace(self.circuit_depths[0], self.circuit_depths[-1], 100) + plt.plot( + circuit_depths_smooth_axis, + rb_decay_curve(np.array(circuit_depths_smooth_axis), A, alpha, B), + color="red", + linestyle="--", + label=f"Exponential Fit" + ) + + plt.text( + 0.5, + 0.95, + f"2Q Clifford Fidelity = {fidelity * 100:.2f}%", + horizontalalignment="center", + verticalalignment="top", + fontdict={"fontsize": "large", "fontweight": "bold"}, + transform=plt.gca().transAxes, ) + plt.xlabel("Circuit Depth") - plt.ylabel("Fidelity") - plt.title("2Q Randomized Benchmarking Fidelity") - plt.legend() + plt.ylabel(fr"Probability to recover to $|00\rangle$") + plt.title("2Q Randomized Benchmarking") + plt.legend(framealpha=0) plt.show() + + def plot_two_qubit_state_distribution(self): + """ + Plot how the two-qubit state is distributed as a function of circuit-depth on average. + """ + plt.plot(self.circuit_depths, (self.data.state == 0).mean(dim="average").mean(dim="repeat").data, + label=r"$|00\rangle$", marker=".", color="c", linewidth=3) + plt.plot(self.circuit_depths, (self.data.state == 1).mean(dim="average").mean(dim="repeat").data, + label=r"$|01\rangle$", marker=".", color="b", linewidth=1) + plt.plot(self.circuit_depths, (self.data.state == 2).mean(dim="average").mean(dim="repeat").data, + label=r"$|10\rangle$", marker=".", color="y", linewidth=1) + plt.plot(self.circuit_depths, (self.data.state == 3).mean(dim="average").mean(dim="repeat").data, + label=r"$|11\rangle$", marker=".", color="r", linewidth=1) + plt.axhline(0.25, color="grey", linestyle="--", linewidth=2, label="2Q mixed-state") + + plt.xlabel("Circuit Depth") + plt.ylabel(fr"Probability to recover to a given state") + plt.title("2Q State Distribution vs. Circuit Depth") + plt.legend(framealpha=0, title="$2Q State $|q_cq_t\rangle$") + plt.show() + + def fit_exponential(self): """ Fits the decay curve of the RB data to an exponential model. @@ -95,7 +143,7 @@ def fit_exponential(self): """ decay_curve = self.get_decay_curve() - popt, _ = curve_fit(rb_decay_curve, self.circuit_depths, decay_curve, p0=[0.75, -0.1, 0.25], maxfev=10000) + popt, _ = curve_fit(rb_decay_curve, self.circuit_depths, decay_curve, p0=[0.75, 0.9, 0.25], maxfev=10000) A, alpha, B = popt return A, alpha, B diff --git a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/TwoQubitRB.py b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/TwoQubitRB.py index 4dbf9bae..0d67d565 100644 --- a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/TwoQubitRB.py +++ b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/TwoQubitRB.py @@ -154,7 +154,13 @@ def _gen_rb_sequence(self, depth): return gate_ids - def _gen_qua_program(self, sequence_depths: list[int], num_repeats: int, num_averages: int, unsafe: bool): + def _gen_qua_program( + self, + sequence_depths: list[int], + num_repeats: int, + num_averages: int, + unsafe: bool + ): with program() as prog: sequence_depth = declare(int) repeat = declare(int) @@ -171,8 +177,8 @@ def _gen_qua_program(self, sequence_depths: list[int], num_repeats: int, num_ave } assign(progress, 0) - with for_each_(sequence_depth, sequence_depths): - with for_(repeat, 0, repeat < num_repeats, repeat + 1): + with for_(repeat, 0, repeat < num_repeats, repeat + 1): + with for_each_(sequence_depth, sequence_depths): assign(progress, progress + 1) save(progress, progress_os) advance_input_stream(gates_len_is) @@ -187,8 +193,9 @@ def _gen_qua_program(self, sequence_depths: list[int], num_repeats: int, num_ave save(state, state_os) with stream_processing(): - state_os.buffer(len(sequence_depths), num_repeats, num_averages).save("state") + state_os.buffer(num_repeats, len(sequence_depths), num_averages).save("state") progress_os.save("progress") + return prog def _input_stream_name(self, element: str): @@ -208,14 +215,14 @@ def _insert_all_input_stream( num_repeats: int, callback: Optional[Callable[[List[int]], None]] = None, ): - for sequence_depth in sequence_depths: - for repeat in range(num_repeats): + for repeat in range(num_repeats): + for sequence_depth in sequence_depths: sequence = self._gen_rb_sequence(sequence_depth) if self._sequence_tracker is not None: self._sequence_tracker.make_sequence(sequence) job.insert_input_stream("__gates_len_is__", len(sequence)) for qe in self._rb_baker.all_elements: - job.insert_input_stream(f"{qe}_is", self._decode_sequence_for_element(qe, sequence)) + job.insert_input_stream(f"{self._input_stream_name(qe)}_is", self._decode_sequence_for_element(qe, sequence)) if callback is not None: callback(sequence) diff --git a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb_example.py b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb_example.py index bf32f2fc..2c6ea114 100644 --- a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb_example.py +++ b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb_example.py @@ -138,6 +138,9 @@ def meas(): res.plot_fidelity() plt.show() +res.plot_two_qubit_state_distribution() +plt.show() + # verify/save the random sequences created during the experiment rb.save_sequences_to_file("sequences.txt") # saves the gates used in each random sequence rb.save_command_mapping_to_file("commands.txt") # saves mapping from "command id" to sequence From 757fbb4143cf9bccb50905032d0a10cf4e2c5478 Mon Sep 17 00:00:00 2001 From: Dean Poulos Date: Fri, 7 Feb 2025 04:59:22 +1100 Subject: [PATCH 04/11] Fix legend title plotting for 2Q state distribution. --- .../characterization/two_qubit_rb/two_qubit_rb/RBResult.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py index 212a4b1c..cb027674 100644 --- a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py +++ b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py @@ -127,7 +127,8 @@ def plot_two_qubit_state_distribution(self): plt.xlabel("Circuit Depth") plt.ylabel(fr"Probability to recover to a given state") plt.title("2Q State Distribution vs. Circuit Depth") - plt.legend(framealpha=0, title="$2Q State $|q_cq_t\rangle$") + plt.legend(framealpha=0, title=r"2Q State $\mathbf{|q_cq_t\rangle}$", + title_fontproperties={"weight": "bold"}) plt.show() From 80e8b22f3c3953a201cf9a174c83ad5125ee4ee5 Mon Sep 17 00:00:00 2001 From: Dean Poulos Date: Fri, 7 Feb 2025 05:04:34 +1100 Subject: [PATCH 05/11] Update changelog. --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 820d4741..9f2d5bcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## [Unreleased] +### Added +- two-qubit rb - Added feature to plot the two qubit state distribution. + +### Fixed +- two-qubit rb - Swapped the order of the circuit_depth and repeat axis for better performance. ## [0.19.0] - 2025-02-07 ### Added From ff45f757464def1672a0aaf21fc6392d16b7d8a7 Mon Sep 17 00:00:00 2001 From: Dean Poulos Date: Fri, 7 Feb 2025 05:05:06 +1100 Subject: [PATCH 06/11] Fix formatting. --- .../callable_from_qua/_callable_from_qua.py | 9 ++-- .../two_qubit_rb/two_qubit_rb/RBResult.py | 53 +++++++++++++------ .../two_qubit_rb/two_qubit_rb/TwoQubitRB.py | 12 ++--- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/qualang_tools/callable_from_qua/_callable_from_qua.py b/qualang_tools/callable_from_qua/_callable_from_qua.py index f524a91d..ec4948f1 100644 --- a/qualang_tools/callable_from_qua/_callable_from_qua.py +++ b/qualang_tools/callable_from_qua/_callable_from_qua.py @@ -79,13 +79,16 @@ def run(self, job: QmJob): class ProgramAddon(ABC): @abstractmethod - def enter_program(self, program: Program): ... # noqa: E704 + def enter_program(self, program: Program): + ... # noqa: E704 @abstractmethod - def exit_program(self, exc_type, exc_val, exc_tb): ... # noqa: E704 + def exit_program(self, exc_type, exc_val, exc_tb): + ... # noqa: E704 @abstractmethod - def execute_program(self, program: Program, quantum_machine: QuantumMachine): ... # noqa: E704 + def execute_program(self, program: Program, quantum_machine: QuantumMachine): + ... # noqa: E704 class QuaCallableEventManager(ProgramAddon): diff --git a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py index cb027674..74abf8a7 100644 --- a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py +++ b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py @@ -80,7 +80,7 @@ def plot_with_fidelity(self): fmt=".", capsize=2, elinewidth=0.5, - color='blue', + color="blue", label="Experimental Data", ) @@ -90,7 +90,7 @@ def plot_with_fidelity(self): rb_decay_curve(np.array(circuit_depths_smooth_axis), A, alpha, B), color="red", linestyle="--", - label=f"Exponential Fit" + label=f"Exponential Fit", ) plt.text( @@ -104,34 +104,55 @@ def plot_with_fidelity(self): ) plt.xlabel("Circuit Depth") - plt.ylabel(fr"Probability to recover to $|00\rangle$") + plt.ylabel(rf"Probability to recover to $|00\rangle$") plt.title("2Q Randomized Benchmarking") plt.legend(framealpha=0) plt.show() - def plot_two_qubit_state_distribution(self): """ Plot how the two-qubit state is distributed as a function of circuit-depth on average. """ - plt.plot(self.circuit_depths, (self.data.state == 0).mean(dim="average").mean(dim="repeat").data, - label=r"$|00\rangle$", marker=".", color="c", linewidth=3) - plt.plot(self.circuit_depths, (self.data.state == 1).mean(dim="average").mean(dim="repeat").data, - label=r"$|01\rangle$", marker=".", color="b", linewidth=1) - plt.plot(self.circuit_depths, (self.data.state == 2).mean(dim="average").mean(dim="repeat").data, - label=r"$|10\rangle$", marker=".", color="y", linewidth=1) - plt.plot(self.circuit_depths, (self.data.state == 3).mean(dim="average").mean(dim="repeat").data, - label=r"$|11\rangle$", marker=".", color="r", linewidth=1) + plt.plot( + self.circuit_depths, + (self.data.state == 0).mean(dim="average").mean(dim="repeat").data, + label=r"$|00\rangle$", + marker=".", + color="c", + linewidth=3, + ) + plt.plot( + self.circuit_depths, + (self.data.state == 1).mean(dim="average").mean(dim="repeat").data, + label=r"$|01\rangle$", + marker=".", + color="b", + linewidth=1, + ) + plt.plot( + self.circuit_depths, + (self.data.state == 2).mean(dim="average").mean(dim="repeat").data, + label=r"$|10\rangle$", + marker=".", + color="y", + linewidth=1, + ) + plt.plot( + self.circuit_depths, + (self.data.state == 3).mean(dim="average").mean(dim="repeat").data, + label=r"$|11\rangle$", + marker=".", + color="r", + linewidth=1, + ) plt.axhline(0.25, color="grey", linestyle="--", linewidth=2, label="2Q mixed-state") plt.xlabel("Circuit Depth") - plt.ylabel(fr"Probability to recover to a given state") + plt.ylabel(rf"Probability to recover to a given state") plt.title("2Q State Distribution vs. Circuit Depth") - plt.legend(framealpha=0, title=r"2Q State $\mathbf{|q_cq_t\rangle}$", - title_fontproperties={"weight": "bold"}) + plt.legend(framealpha=0, title=r"2Q State $\mathbf{|q_cq_t\rangle}$", title_fontproperties={"weight": "bold"}) plt.show() - def fit_exponential(self): """ Fits the decay curve of the RB data to an exponential model. diff --git a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/TwoQubitRB.py b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/TwoQubitRB.py index 0d67d565..52f7063e 100644 --- a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/TwoQubitRB.py +++ b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/TwoQubitRB.py @@ -154,13 +154,7 @@ def _gen_rb_sequence(self, depth): return gate_ids - def _gen_qua_program( - self, - sequence_depths: list[int], - num_repeats: int, - num_averages: int, - unsafe: bool - ): + def _gen_qua_program(self, sequence_depths: list[int], num_repeats: int, num_averages: int, unsafe: bool): with program() as prog: sequence_depth = declare(int) repeat = declare(int) @@ -222,7 +216,9 @@ def _insert_all_input_stream( self._sequence_tracker.make_sequence(sequence) job.insert_input_stream("__gates_len_is__", len(sequence)) for qe in self._rb_baker.all_elements: - job.insert_input_stream(f"{self._input_stream_name(qe)}_is", self._decode_sequence_for_element(qe, sequence)) + job.insert_input_stream( + f"{self._input_stream_name(qe)}_is", self._decode_sequence_for_element(qe, sequence) + ) if callback is not None: callback(sequence) From 8fe4fe10e380ce05248b8788bdacf56b2c40ac4b Mon Sep 17 00:00:00 2001 From: Dean Poulos Date: Sat, 8 Feb 2025 01:29:19 +1100 Subject: [PATCH 07/11] Revert incidental change to callable from qua. --- qualang_tools/callable_from_qua/_callable_from_qua.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/qualang_tools/callable_from_qua/_callable_from_qua.py b/qualang_tools/callable_from_qua/_callable_from_qua.py index ec4948f1..f524a91d 100644 --- a/qualang_tools/callable_from_qua/_callable_from_qua.py +++ b/qualang_tools/callable_from_qua/_callable_from_qua.py @@ -79,16 +79,13 @@ def run(self, job: QmJob): class ProgramAddon(ABC): @abstractmethod - def enter_program(self, program: Program): - ... # noqa: E704 + def enter_program(self, program: Program): ... # noqa: E704 @abstractmethod - def exit_program(self, exc_type, exc_val, exc_tb): - ... # noqa: E704 + def exit_program(self, exc_type, exc_val, exc_tb): ... # noqa: E704 @abstractmethod - def execute_program(self, program: Program, quantum_machine: QuantumMachine): - ... # noqa: E704 + def execute_program(self, program: Program, quantum_machine: QuantumMachine): ... # noqa: E704 class QuaCallableEventManager(ProgramAddon): From 38d2f2d6a909a6f070481b95e550f77889e79c27 Mon Sep 17 00:00:00 2001 From: Dean Poulos Date: Sat, 8 Feb 2025 02:15:35 +1100 Subject: [PATCH 08/11] Make linter happy. --- .../characterization/two_qubit_rb/two_qubit_rb/RBResult.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py index 74abf8a7..fdd641b5 100644 --- a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py +++ b/qualang_tools/characterization/two_qubit_rb/two_qubit_rb/RBResult.py @@ -90,7 +90,7 @@ def plot_with_fidelity(self): rb_decay_curve(np.array(circuit_depths_smooth_axis), A, alpha, B), color="red", linestyle="--", - label=f"Exponential Fit", + label="Exponential Fit", ) plt.text( @@ -104,7 +104,7 @@ def plot_with_fidelity(self): ) plt.xlabel("Circuit Depth") - plt.ylabel(rf"Probability to recover to $|00\rangle$") + plt.ylabel(r"Probability to recover to $|00\rangle$") plt.title("2Q Randomized Benchmarking") plt.legend(framealpha=0) plt.show() @@ -148,7 +148,7 @@ def plot_two_qubit_state_distribution(self): plt.axhline(0.25, color="grey", linestyle="--", linewidth=2, label="2Q mixed-state") plt.xlabel("Circuit Depth") - plt.ylabel(rf"Probability to recover to a given state") + plt.ylabel(r"Probability to recover to a given state") plt.title("2Q State Distribution vs. Circuit Depth") plt.legend(framealpha=0, title=r"2Q State $\mathbf{|q_cq_t\rangle}$", title_fontproperties={"weight": "bold"}) plt.show() From ab1cdf5686a3a722c39069c3cb308c3041c3598e Mon Sep 17 00:00:00 2001 From: Dean Poulos Date: Tue, 18 Feb 2025 12:37:38 +1100 Subject: [PATCH 09/11] Move two_qubit_rb_example to examples. --- .../two_qubit_rb_example.py => examples/two_qubit_rb.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename qualang_tools/characterization/two_qubit_rb/two_qubit_rb_example.py => examples/two_qubit_rb.py (100%) diff --git a/qualang_tools/characterization/two_qubit_rb/two_qubit_rb_example.py b/examples/two_qubit_rb.py similarity index 100% rename from qualang_tools/characterization/two_qubit_rb/two_qubit_rb_example.py rename to examples/two_qubit_rb.py From 7b172d95b2eec919adc23ab8bf62f34394bc1d03 Mon Sep 17 00:00:00 2001 From: Dean Poulos Date: Tue, 18 Feb 2025 12:39:27 +1100 Subject: [PATCH 10/11] Update example link in README. --- qualang_tools/characterization/two_qubit_rb/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qualang_tools/characterization/two_qubit_rb/README.md b/qualang_tools/characterization/two_qubit_rb/README.md index 36f6c9c5..12d10b0a 100644 --- a/qualang_tools/characterization/two_qubit_rb/README.md +++ b/qualang_tools/characterization/two_qubit_rb/README.md @@ -37,7 +37,7 @@ res = rb.run( ) ``` -[Here](two_qubit_rb_example.py) is an example for flux-tunable transmon qubits. +[Here](/examples/two_qubit_rb_example.py) is an example for flux-tunable transmon qubits. ## Introduction Two-Qubit Randomized Benchmarking (RB) has become a popular protocol that allows to experimentally quantify the performance of a quantum processor by applying sequences of randomly sampled Clifford gates and measuring the average error rate. Due to its universality it has been implemented in various qubit platforms such as trapped-ions [^1], NMR [^2], spin [^3] and superconducting qubits [^4]. Two-Qubit RB can be challenging to implement with state-of-the-art control electronics because of the necessity to sample from a large Clifford gate set. The Clifford group consists of 11520 operations [^4] and contains the single qubit Clifford operations (576), the CNOT-like class (5184), the iSWAP-like class (5184) and the SWAP-like class (576). In the provided example we introduce an implementation on the OPX+ using the current version of the generic `TwoQubitRb` class. The implementation exploits the [baking](https://github.com/qua-platform/py-qua-tools/blob/main/qualang_tools/bakery/README.md) tool to generate the individual Clifford operations. The class then uses the [Input Stream](https://docs.quantum-machines.co/latest/qm-qua-sdk/docs/Guides/features/?h=declare_input_stream#input-streams) feature to send a string of Clifford indices to the OPX that represent the executed gate sequence which is terminated with the inverse operation. The execution is based on the [Switch Case](https://docs.quantum-machines.co/latest/qm-qua-sdk/docs/Guides/features/?h=switch#switch-case) flow control of QUA, which sets the current minimal gate duration limit to 40 ns.