Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 164 additions & 0 deletions docs/apidocs/design_doc_for_new_rb.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "275dc913",
"metadata": {},
"source": [
"# Design document for new algorithm for randomized-benchmarking experiments, using transpiled Cliffords"
]
},
{
"cell_type": "markdown",
"id": "afe2a51d",
"metadata": {},
"source": [
"## Main ideas:\n",
"There are three main ideas in the new algorithm:\n",
"1.\tFor every Clifford, store its transpiled circuit. This way we can build the RB circuit out of transpiled Cliffords. In this way, we avoid transpilation of the entire circuit, which is the bottleneck in terms of performance for the current algorithm. We call this transpiled Cliffords.\n",
"\n",
"2.\tCreate a 1-1 mapping between Cliffords and integers. This enables group operations such as compose and inverse to be performed on the equivalent group of integers, rather than on the Clifford group. The computations for compose and inverse on integers are stored in advance. We call this Clifford data.\n",
"\n",
"3.\tFor the compose operation (◦), the full table of all compose results is very large: $11520 \\times 11520 = 132,710,400$. \n",
"We notice that for $A ◦ B$, we can replace it by $A ◦ B_0 ◦ B_1 ◦.… ◦B_k$, where $B = B_0 ◦ B_1 ◦.… ◦B_k$ and $B_i$ are Cliffords consisting of a single gate, $0 ≤ i ≤ k$. Therefore, it is sufficient to store only the results of all $A ◦ G$, where $G$ represents the single gate Cliffords. We identified 20 single-gate Cliffords, thus reducing the number of compose results to $11520 X 20 = 230,400$.\n"
]
},
{
"cell_type": "markdown",
"id": "a8ec48d9",
"metadata": {},
"source": [
"## Preprocessing\n",
"1.\tCreate the Clifford data by invoking the file `create_clifford_map.py`. The data is stored in a file called `clifford_data.py`.\n",
"2.\tGenerate the transpiled Cliffords by invoking the file `generate_transpiled_circuits.py`. The data is stored in a file named `transpiled_circs_<suffix>.qpy`, where suffix indicates the number of qubits and the basis gates for which we transpiled. There are currently two such files that can be used as defaults: `transpiled_circs_2q_rz_sx_cx.qpy` and `transpiled_circs_2q_x_h_s_cx.qpy` and similar files for 1 qubit. \n",
"3. All these files are under \n",
"`qiskit_experiments/library/randomized_benchmarking/`.\n"
]
},
{
"cell_type": "markdown",
"id": "fd55c9aa",
"metadata": {},
"source": [
"## Main changes in StandardRB class\n",
"\n",
"We add two new fields: transpiled_cliff_circuits[1] and transpiled_cliff_circuits[2]\n",
"These are initialized in __init__() to None. Later, in circuits() the transpiled circuits are loaded from the file into one of these.\n",
"Note that here, as well as in other places, we limit the number of qubits to 1 or 2. This is intentional, as the algorithm will not work for more than 2 qubits.\n",
"The question is how to deal with more than 2 qubits.\n",
"I can think of two ways to resolve this – keep the old code alongside the new code using `if n > 2` statements. Or separate this into 2 different experiments – one for 1-2 qubits and the other for more. **Any suggestions?**\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "7c7b0e7c",
"metadata": {},
"source": [
"## User perspective – main changes\n",
"1. The user must define the basis gates in the `transpile_options`. We can define a default for the basis gates:[“rz”, “sx”, “cx”]. **Should we have a default or should it be mandatory to specify the basis gates?**\n",
"\n",
"2. Depending on the basis gates, the user may wish to generate a new `transpiled_circs` file. \n",
"I see two options regarding how this should be done:\n",
"* The user must run `generate_transpiled_circuits.py` in advance, to create the suitable file. If the file does not exist, an exception will be raised during the call to `circuits()`.\n",
"* The user can provide a file name with a full path, and if that file exists, it will be loaded during the call to `circuits()`. If it does not exist, it will be generated during `circuits()`.\n",
"If no file name is specified, the file will be created with a default name in the cwd.\n",
"\n",
"**Any inputs on this?**\n"
]
},
{
"cell_type": "markdown",
"id": "1c30fd5c",
"metadata": {},
"source": [
"## Main new methods\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d65cd1ef",
"metadata": {},
"outputs": [],
"source": [
"def circuits(self) -> List[QuantumCircuit]: # replacing the existing circuits() method\n",
" rng = default_rng(seed=self.experiment_options.seed)\n",
" circuits = []\n",
" if not hasattr(self.transpile_options, \"basis_gates\"):\n",
" raise QiskitError(\"transpile_options.basis_gates must be set for rb_experiment\")\n",
"\n",
" self.load_transpiled_cliff_circuits()\n",
" for _ in range(self.experiment_options.num_samples):\n",
" rb_circuits, _ = self._build_rb_circuits(self.experiment_options.lengths, rng)\n",
" circuits += rb_circuits\n",
" return circuits"
]
},
{
"cell_type": "markdown",
"id": "202181d1",
"metadata": {},
"source": [
"The class `InterleavedRB` implements `circuits()` in a similar manner.\n",
"The method `_build_rb_circuits()` does the construction of the rb circuits using the transpiled cliffords as building blocks. It replaces the existing methods ` _sample_circuits()` and `_generate_circuit()`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9d78aef2",
"metadata": {},
"outputs": [],
"source": [
"def _layout_for_rb(self):"
]
},
{
"cell_type": "markdown",
"id": "3a09349e",
"metadata": {},
"source": [
"The above method does a quick layout to avoid calling `transpile()` which is very costly in performance. We simply copy the circuit to a new circuit where we define the mapping of the qubit to the single physical qubit that was requested by the user. Something similar is done in `ParallelExperiment._combined_circuits`.\n",
"It copies `self.circuits()` to a new list of circuits, while creating the trivial layout."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ee2e56e2",
"metadata": {},
"outputs": [],
"source": [
"def _transpiled_circuits(self) -> List[QuantumCircuit]:\n",
" \"\"\"Return a list of experiment circuits, transpiled.\"\"\"\n",
" transpiled = self._layout_for_rb()\n",
" if self.analysis.options.get(\"gate_error_ratio\", None) is None:\n",
" # Gate errors are not computed, then counting ops is not necessary.\n",
" return transpiled\n",
" # the remainder of this method is the same as in the existing version"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}