From 3b9811a6ea99e5a704c99826d27506dd9514cd89 Mon Sep 17 00:00:00 2001 From: Paul Nation Date: Fri, 3 Sep 2021 16:50:09 -0400 Subject: [PATCH] Add QV tutorial --- tutorials/03_qv_example.ipynb | 281 ++++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 tutorials/03_qv_example.ipynb diff --git a/tutorials/03_qv_example.ipynb b/tutorials/03_qv_example.ipynb new file mode 100644 index 00000000..61f05d75 --- /dev/null +++ b/tutorials/03_qv_example.ipynb @@ -0,0 +1,281 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "54191476", + "metadata": {}, + "source": [ + "# Quantum Volume\n", + "\n", + "Here we show off using the expectation value functionality of the M3 distribution classes using Quantum Volume (QV) as an example. Here we formulate QV as an expectation value of a projector onto the heavy-output elements on a distribution." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "c1b69009", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from qiskit import *\n", + "from qiskit.quantum_info import Statevector\n", + "from qiskit.circuit.library import QuantumVolume\n", + "import mthree" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cdd59933", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit.test.mock import FakeAthens\n", + "noisy_sim = FakeAthens()" + ] + }, + { + "cell_type": "markdown", + "id": "0118fe34", + "metadata": {}, + "source": [ + "QV is defined in terms of heavy-ouputs of a distribution. Heavy-outputs are those bit-strings that are those that have probabilities above the median value of the distribution. Below we define the projection operator onto the set of bit-strings that are heavy-outputs for a given distribution." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ccf57f8b", + "metadata": {}, + "outputs": [], + "source": [ + "def heavy_projector(qv_probs):\n", + " \"\"\"Forms the projection operator onto the heavy-outputs of a given probability distribution.\n", + " \n", + " Parameters:\n", + " qv_probs (dict): A dictionary of bitstrings and associated probabilities.\n", + " \n", + " Returns:\n", + " dict: Projector onto the heavy-set.\n", + " \"\"\"\n", + " median_prob = np.median(list(qv_probs.values()))\n", + " heavy_strs = {}\n", + " for key, val in qv_probs.items():\n", + " if val > median_prob:\n", + " heavy_strs[key] = 1\n", + " return heavy_strs" + ] + }, + { + "cell_type": "markdown", + "id": "2134ff49", + "metadata": {}, + "source": [ + "First we begin by calibrating our M3 mitigator over all the qubits on our noisy simulator. (We use the `independent` method since it is much faster to do so on a simulator.)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "254a4dbe", + "metadata": {}, + "outputs": [], + "source": [ + "mit = mthree.M3Mitigation(noisy_sim)\n", + "mit.cals_from_system(method='independent')" + ] + }, + { + "cell_type": "markdown", + "id": "1b267a08", + "metadata": {}, + "source": [ + "Now we generate 10 QV circuits as our dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "2db632a1", + "metadata": {}, + "outputs": [], + "source": [ + "# Generate QV circuits\n", + "N = 10\n", + "qv_circs = [QuantumVolume(5) for _ in range(N)]" + ] + }, + { + "cell_type": "markdown", + "id": "e0698f04", + "metadata": {}, + "source": [ + "Next, we have to determine the heavy-set of each circuit from the ideal answer, and then pass this along to our heavy-set projector function that we defined above." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "911f8110", + "metadata": {}, + "outputs": [], + "source": [ + "# Compute ideal distributions and projectors on the heavy set.\n", + "ideal_probs = [Statevector.from_instruction(circ).probabilities_dict() for circ in qv_circs]\n", + "heavy_projectors = [heavy_projector(probs) for probs in ideal_probs]" + ] + }, + { + "cell_type": "markdown", + "id": "f45f1074", + "metadata": {}, + "source": [ + "Now, in preparation for actual execution, we add measurements to the end of our QV circuits, and compile them for the target device" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "87e116f2", + "metadata": {}, + "outputs": [], + "source": [ + "# Add meauserements to circuits and transpile\n", + "trans_circs = transpile([circ.measure_all(inplace=False) for circ in qv_circs], noisy_sim,\n", + " layout_method='sabre', routing_method='sabre', optimization_level=3)" + ] + }, + { + "cell_type": "markdown", + "id": "460e1859", + "metadata": {}, + "source": [ + "Because the SWAP mapping of the circuit permutes the qubit states, we need the final measurement mapping for each circuit to know which physical qubit corresponds to each measured bit:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "f2b71415", + "metadata": {}, + "outputs": [], + "source": [ + "# Determine final qubit mappings\n", + "qubits = [list(mthree.utils.final_measurement_mapping(circ)) for circ in trans_circs]" + ] + }, + { + "cell_type": "markdown", + "id": "5257a761", + "metadata": {}, + "source": [ + "We are now ready to execute the circuits on the target backend, and mitigate the resulting raw counts:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "39b5d818", + "metadata": {}, + "outputs": [], + "source": [ + "# Execute circuits and mitigate\n", + "raw_counts = noisy_sim.run(trans_circs, shots=8192).result().get_counts()\n", + "quasi_collection = mit.apply_correction(raw_counts, qubits)" + ] + }, + { + "cell_type": "markdown", + "id": "32b82cd1", + "metadata": {}, + "source": [ + "The value needed to determine if each circuit represents a passing QV value is determined by the expectation value of the heavy projector for each circuit:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "b8136595", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.64273103, 0.73990926, 0.7367156 , 0.68290608, 0.7421638 ,\n", + " 0.66162356, 0.70204107, 0.67630205, 0.73943566, 0.73140044])" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Determine expectation value of heavy set prjector\n", + "expvals = quasi_collection.expval(heavy_projectors)\n", + "expvals" + ] + }, + { + "cell_type": "markdown", + "id": "42880efe", + "metadata": {}, + "source": [ + "A passing QV score is one where the expectation value is above 2/3:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "ac23ea82", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([False, True, True, True, True, False, True, True, True,\n", + " True])" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Check if the scores are passing or not\n", + "expvals > 2/3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93b1ff8d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.9.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}