Skip to content

Commit

Permalink
Rework tutorials to use the new workflow (#404)
Browse files Browse the repository at this point in the history
  • Loading branch information
caleb-johnson authored Sep 12, 2023
1 parent 26e58eb commit 5224cda
Show file tree
Hide file tree
Showing 4 changed files with 327 additions and 269 deletions.
2 changes: 1 addition & 1 deletion docs/circuit_cutting/explanation/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Much of the circuit cutting literature describes a process where we sample from

Current limitations
-------------------
* ``PauliList`` is the only supported observable format until no sooner than CKT v0.4.0.
* ``PauliList`` is the only supported observable format until no sooner than CKT v0.5.0.

References
----------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,10 @@
"Like any circuit knitting technique, gate cutting can be described as three consecutive steps:\n",
"\n",
"- **cut** some non-local gates in the circuit and possibly separate the circuit into subcircuits\n",
"- **execute** many sampled subexperiments on the backend(s)\n",
"- **execute** many sampled subexperiments using the Qiskit Sampler primitive\n",
"- **reconstruct** the expectation value of the full-sized circuit"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "1e710888",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from qiskit.circuit.library import EfficientSU2\n",
"from qiskit.quantum_info import PauliList\n",
"from qiskit_aer.primitives import Estimator, Sampler\n",
"\n",
"from circuit_knitting.cutting import (\n",
" partition_problem,\n",
" execute_experiments,\n",
" reconstruct_expectation_values,\n",
")"
]
},
{
"cell_type": "markdown",
"id": "510910a6",
Expand All @@ -45,7 +26,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 1,
"id": "96f5b72a",
"metadata": {},
"outputs": [
Expand All @@ -56,16 +37,18 @@
"<Figure size 831.997x294.311 with 1 Axes>"
]
},
"execution_count": 2,
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"circuit = EfficientSU2(4, entanglement=\"linear\", reps=2).decompose()\n",
"circuit.assign_parameters([0.4] * len(circuit.parameters), inplace=True)\n",
"from qiskit.circuit.library import EfficientSU2\n",
"\n",
"qc = EfficientSU2(4, entanglement=\"linear\", reps=2).decompose()\n",
"qc.assign_parameters([0.4] * len(qc.parameters), inplace=True)\n",
"\n",
"circuit.draw(\"mpl\", scale=0.8)"
"qc.draw(\"mpl\", scale=0.8)"
]
},
{
Expand All @@ -75,16 +58,18 @@
"source": [
"### Specify some observables\n",
"\n",
"Currently, only `Pauli` observables with phase equal to 1 are supported. Full support for `SparsePauliOp` is expected in CKT v0.4.0."
"Currently, only `Pauli` observables with phase equal to 1 are supported. Full support for `SparsePauliOp` is expected in CKT v0.5.0."
]
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 2,
"id": "f75e8dd1",
"metadata": {},
"outputs": [],
"source": [
"from qiskit.quantum_info import PauliList\n",
"\n",
"observables = PauliList([\"ZZII\", \"IZZI\", \"IIZZ\", \"XIXI\", \"ZIZZ\", \"IXIX\"])"
]
},
Expand All @@ -100,31 +85,21 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 3,
"id": "30326299",
"metadata": {},
"outputs": [],
"source": [
"from circuit_knitting.cutting import partition_problem\n",
"\n",
"partitioned_problem = partition_problem(\n",
" circuit=circuit, partition_labels=\"AABB\", observables=observables\n",
" circuit=qc, partition_labels=\"AABB\", observables=observables\n",
")\n",
"subcircuits = partitioned_problem.subcircuits\n",
"subobservables = partitioned_problem.subobservables\n",
"bases = partitioned_problem.bases"
]
},
{
"cell_type": "markdown",
"id": "3518e2df",
"metadata": {},
"source": [
"`partition_problem` returns a data structure that includes:\n",
"\n",
"- `subcircuits`: a `Dict` mapping partition labels to subcircuits\n",
"- `subobservables`: a `Dict` mapping partition labels to subobservables\n",
"- `bases`: a `list` of ``QPDBasis`` instances, one for each decomposed instruction"
]
},
{
"cell_type": "markdown",
"id": "9d2d42c3",
Expand All @@ -135,7 +110,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 4,
"id": "6b54be63",
"metadata": {},
"outputs": [
Expand All @@ -146,7 +121,7 @@
" 'B': PauliList(['ZZ', 'IZ', 'II', 'XI', 'ZI', 'IX'])}"
]
},
"execution_count": 5,
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -157,7 +132,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 5,
"id": "b7e06fac",
"metadata": {},
"outputs": [
Expand All @@ -168,7 +143,7 @@
"<Figure size 913.147x160.533 with 1 Axes>"
]
},
"execution_count": 6,
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -179,7 +154,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 6,
"id": "11e45e83",
"metadata": {},
"outputs": [
Expand All @@ -190,7 +165,7 @@
"<Figure size 913.309x160.533 with 1 Axes>"
]
},
"execution_count": 7,
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
Expand Down Expand Up @@ -220,7 +195,7 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 7,
"id": "3d606ef8",
"metadata": {},
"outputs": [
Expand All @@ -233,19 +208,43 @@
}
],
"source": [
"import numpy as np\n",
"\n",
"print(f\"Sampling overhead: {np.prod([basis.overhead for basis in bases])}\")"
]
},
{
"cell_type": "markdown",
"id": "495ce676",
"id": "ef3b061c-cd1d-4931-85f6-155e00b355be",
"metadata": {},
"source": [
"### Generate and run the cutting experiments\n",
"### Generate the subexperiments to run on the backend\n",
"\n",
"`execute_experiments` accepts `circuits`/`subobservables` args as dictionaries mapping qubit partition labels to the respective `subcircuit`/`subobservables`.\n",
"`generate_cutting_experiments` accepts `circuits`/`observables` args as dictionaries mapping qubit partition labels to the respective `subcircuit`/`subobservables`.\n",
"\n",
"To simulate the expectation value of the full-sized circuit, many subexperiments are generated from the decomposed gates' joint quasiprobability distribution and then executed on one or more backends. The number of samples taken from the distribution is controlled by `num_samples`, and one combined weight is given for each unique sample. For more information on how the weights are calculated, refer to the [explanatory material](../explanation/index.rst)."
"To simulate the expectation value of the full-sized circuit, many subexperiments are generated from the decomposed gates' joint quasiprobability distribution and then executed on one or more backends. The number of samples taken from the distribution is controlled by `num_samples`, and one combined coefficient is given for each unique sample. For more information on how the coefficients are calculated, refer to the [explanatory material](../explanation/index.rst)."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "2029d18e-0e91-4160-b8c9-02cb9e1ba3cb",
"metadata": {},
"outputs": [],
"source": [
"from circuit_knitting.cutting import generate_cutting_experiments\n",
"\n",
"subexperiments, coefficients = generate_cutting_experiments(\n",
" circuits=subcircuits, observables=subobservables, num_samples=np.inf\n",
")"
]
},
{
"cell_type": "markdown",
"id": "d8870454-2173-4454-90b4-a034779510e0",
"metadata": {},
"source": [
"### Run the subexperiments using the Qiskit Sampler primitive"
]
},
{
Expand All @@ -255,30 +254,50 @@
"metadata": {},
"outputs": [],
"source": [
"# Keep in mind, Terra Sampler does not support mid-circuit measurements at all,\n",
"# and Aer Sampler does not support mid-circuit measurements when shots==None.\n",
"from qiskit_aer.primitives import Sampler\n",
"\n",
"# Set up a Qiskit Aer Sampler primitive for each circuit partition\n",
"samplers = {\n",
" \"A\": Sampler(run_options={\"shots\": 2**12}),\n",
" \"B\": Sampler(run_options={\"shots\": 2**12}),\n",
" label: Sampler(run_options={\"shots\": 2**12}) for label in subexperiments.keys()\n",
"}\n",
"\n",
"quasi_dists, coefficients = execute_experiments(\n",
" circuits=subcircuits,\n",
" subobservables=subobservables,\n",
" num_samples=np.inf,\n",
" samplers=samplers,\n",
")"
"# Retrieve results from each partition's subexperiments\n",
"results = {\n",
" label: sampler.run(subexperiments[label]).result()\n",
" for label, sampler in samplers.items()\n",
"}"
]
},
{
"cell_type": "markdown",
"id": "a1482b93",
"id": "68eb0522-8c01-4f56-aacc-0bfc60159896",
"metadata": {},
"source": [
"`execute_experiments` returns:\n",
"\n",
"- A 3D list of length-2 tuples containing a quasiprobability distribution and QPD bit information for each unique subexperiment\n",
"- The coefficients for each subexperiment"
"To use the Qiskit Runtime Sampler, replace the code above with this commented block."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "3c9a7e78-4bf9-4dbd-a8f9-3db185591d9c",
"metadata": {},
"outputs": [],
"source": [
"# from qiskit_ibm_runtime import Session, Options, Sampler\n",
"#\n",
"# with Session(backend=\"ibmq_qasm_simulator\") as session:\n",
"# # Set up Qiskit Runtime Sampler primitives.\n",
"# samplers = {\n",
"# label: Sampler(Options(execution={\"shots\": 2**12})) for label in subexperiments.keys()\n",
"# }\n",
"#\n",
"# # Retrieve results from each subexperiment\n",
"# results = {\n",
"# label: sampler.run(subexperiments[label]).result()\n",
"# for label, sampler in samplers.items()\n",
"# }\n",
"#\n",
"# session.close()"
]
},
{
Expand All @@ -287,31 +306,32 @@
"metadata": {},
"source": [
"### Reconstruct the expectation values\n",
"`reconstruct_expectation_values` expects `quasi_dists` and `coefficients` in the same format as returned from `execute_experiments`. `quasi_dists` is a 3D list of shape (`num_unique_samples`, `num_partitions`, `num_commuting_observ_groups`), and `coefficients` is a list with length equal to the number of unique samples. `subobservables` is the dictionary mapping qubit partition label to the associated subobservable(s), as output from `decompose_problem` above."
"\n",
"Use the subexperiment results, subobservables, and sampling coefficients to reconstruct the expectation value of the original circuit.\n",
"\n",
"Include the number of bits used for cutting measurements in the results metadata. This will be automated in a future release, but users must specify it manually for now."
]
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 11,
"id": "7d57339c",
"metadata": {},
"outputs": [],
"source": [
"from circuit_knitting.cutting import reconstruct_expectation_values\n",
"\n",
"for label, circuits in subexperiments.items():\n",
" for i, circuit in enumerate(circuits):\n",
" results[label].metadata[i][\"num_qpd_bits\"] = len(circuit.cregs[0])\n",
"\n",
"reconstructed_expvals = reconstruct_expectation_values(\n",
" quasi_dists,\n",
" results,\n",
" coefficients,\n",
" subobservables,\n",
")"
]
},
{
"cell_type": "markdown",
"id": "b546c0c4",
"metadata": {},
"source": [
"The output of `reconstruct_expectation_values` is a list of expectation values reconstructed from the smaller subexperiments -- one for each observable."
]
},
{
"cell_type": "markdown",
"id": "53beaca3",
Expand All @@ -322,25 +342,27 @@
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 12,
"id": "e3385ba5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Simulated expectation values: [0.3519755, 0.51862508, 0.6226452, 0.12015682, 0.23095906, -0.14471573]\n",
"Reconstructed expectation values: [0.37551016, 0.52859873, 0.58741736, 0.12230408, 0.29614246, -0.1243059]\n",
"Exact expectation values: [0.36916216, 0.52511814, 0.59161991, 0.10927476, 0.28001606, -0.12940509]\n",
"Errors in estimation: [-0.01718666, -0.00649306, 0.03102529, 0.01088207, -0.04905701, -0.01531064]\n",
"Relative errors in estimation: [-0.04655586, -0.01236495, 0.05244125, 0.09958448, -0.17519354, 0.1183156]\n"
"Errors in estimation: [0.00634799, 0.00348059, -0.00420255, 0.01302933, 0.01612639, 0.00509918]\n",
"Relative errors in estimation: [0.01719568, 0.0066282, -0.00710346, 0.11923456, 0.05759096, -0.0394048]\n"
]
}
],
"source": [
"from qiskit_aer.primitives import Estimator\n",
"\n",
"estimator = Estimator(run_options={\"shots\": None}, approximation=True)\n",
"exact_expvals = (\n",
" estimator.run([circuit] * len(observables), list(observables)).result().values\n",
" estimator.run([qc] * len(observables), list(observables)).result().values\n",
")\n",
"print(\n",
" f\"Reconstructed expectation values: {[np.round(reconstructed_expvals[i], 8) for i in range(len(exact_expvals))]}\"\n",
Expand All @@ -358,14 +380,14 @@
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": 13,
"id": "1faa748e",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<h3>Version Information</h3><table><tr><th>Qiskit Software</th><th>Version</th></tr><tr><td><code>qiskit-terra</code></td><td>0.24.1</td></tr><tr><td><code>qiskit-aer</code></td><td>0.12.1</td></tr><tr><td><code>qiskit-ibmq-provider</code></td><td>0.20.2</td></tr><tr><td><code>qiskit</code></td><td>0.43.2</td></tr><tr><td><code>qiskit-nature</code></td><td>0.6.0</td></tr><tr><th>System information</th></tr><tr><td>Python version</td><td>3.8.16</td></tr><tr><td>Python compiler</td><td>Clang 14.0.6 </td></tr><tr><td>Python build</td><td>default, Mar 1 2023 21:19:10</td></tr><tr><td>OS</td><td>Darwin</td></tr><tr><td>CPUs</td><td>8</td></tr><tr><td>Memory (Gb)</td><td>32.0</td></tr><tr><td colspan='2'>Mon Aug 14 08:36:03 2023 CDT</td></tr></table>"
"<h3>Version Information</h3><table><tr><th>Software</th><th>Version</th></tr><tr><td><code>qiskit</code></td><td>0.44.1</td></tr><tr><td><code>qiskit-terra</code></td><td>0.25.1</td></tr><tr><td><code>qiskit_aer</code></td><td>0.12.1</td></tr><tr><td><code>qiskit_ibm_provider</code></td><td>0.6.3</td></tr><tr><th colspan='2'>System information</th></tr><tr><td>Python version</td><td>3.8.16</td></tr><tr><td>Python compiler</td><td>Clang 14.0.6 </td></tr><tr><td>Python build</td><td>default, Mar 1 2023 21:19:10</td></tr><tr><td>OS</td><td>Darwin</td></tr><tr><td>CPUs</td><td>8</td></tr><tr><td>Memory (Gb)</td><td>32.0</td></tr><tr><td colspan='2'>Mon Sep 11 16:23:04 2023 CDT</td></tr></table>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
Expand Down
Loading

0 comments on commit 5224cda

Please sign in to comment.