{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "fad91a68",
      "metadata": {},
      "source": [
        "---\n",
        "title: Quantum circuit optimization\n",
        "description: This lesson will address several aspects of circuit optimization in quantum computing.\n",
        "---\n",
        "\n",
        "# Quantum circuit optimization\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Toshinari Itoko (21 June 2024)\n",
        "\n",
        "  [Download the pdf](https://ibm.ent.box.com/public/static/0hvvgr1gnwx64x2ukgk04sss6sxc4zko.zip) of the original lecture. Note that some code snippets might become deprecated since these are static images.\n",
        "\n",
        "  *Approximate QPU time to run this experiment is 15 s.*\n",
        "\n",
        "  (Note: Some cells of part 2 are copied from the notebook \"Qiskit Deep dive\", written by Matthew Treinish (Qiskit maintainer))\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "38cf024b",
      "metadata": {},
      "outputs": [],
      "source": [
        "# !pip install 'qiskit[visualization]'\n",
        "# !pip install qiskit_ibm_runtime qiskit_aer\n",
        "# !pip install jupyter\n",
        "# !pip install matplotlib pylatexenc pydot pillow"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "5bc656fa-6376-436e-adfc-59676edc719b",
      "metadata": {
        "editable": true,
        "slideshow": {
          "slide_type": ""
        },
        "tags": []
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'2.0.2'"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit\n",
        "\n",
        "qiskit.__version__"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "b5d0220b",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'0.40.1'"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit_ibm_runtime\n",
        "\n",
        "qiskit_ibm_runtime.__version__"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "1032e247",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'0.17.1'"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit_aer\n",
        "\n",
        "qiskit_aer.__version__"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "335804e7",
      "metadata": {},
      "source": [
        "## 1. Introduction\n",
        "\n",
        "This lesson will address several aspects of circuit optimization in quantum computing. Specifically, we will see the value of circuit optimization by using optimization settings built into Qiskit. Then we will go a bit deeper and see what you can do as an expert in your particular application area to build circuits in a smart way. Finally, we will take a close look at what goes on during transpilation that helps us optimize our circuits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "187c0ab1",
      "metadata": {},
      "source": [
        "## 2. Circuit optimization matters\n",
        "\n",
        "We first compare the results of running 5-qubit GHZ state ($\\frac{1}{\\sqrt{2}} \\left( |00000\\rangle + |11111\\rangle \\right)$) preparation circuits with and without optimization.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "b1570aa9",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.circuit import QuantumCircuit\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "from qiskit.primitives import BackendSamplerV2 as Sampler"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f6be6161",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_ibm_runtime.fake_provider import FakeBrisbane\n",
        "\n",
        "backend = FakeBrisbane()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9cb38fa1",
      "metadata": {},
      "source": [
        "We first use a GHZ circuit naively synthesized as follows.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "262b97e5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/262b97e5-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "num_qubits = 5\n",
        "\n",
        "ghz_circ = QuantumCircuit(num_qubits)\n",
        "ghz_circ.h(0)\n",
        "[ghz_circ.cx(0, i) for i in range(1, num_qubits)]\n",
        "ghz_circ.measure_all()\n",
        "ghz_circ.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f5134657",
      "metadata": {},
      "source": [
        "### 2.1 Optimization level\n",
        "\n",
        "There are 4 available `optimization_level`s from 0-3. The higher the optimization level the more computational effort is spent to optimize the circuit. Level 0 performs no optimization and just does the minimal amount of work to make the circuit runnable on the selected backend. Level 3 spends the most amount if effort (and typically runtime) to try to optimize the circuit. Level 1 is the default optimization level.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ed964d46",
      "metadata": {},
      "source": [
        "We transpile the circuit without optimization (`optimization_level=0`) and with optimization (`optimization_level=2`).\n",
        "We see a big difference in the circuit length of transpiled circuits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "042d2bbc",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "optimization_level=0:\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/042d2bbc-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "optimization_level=2:\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/042d2bbc-3.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "pm0 = generate_preset_pass_manager(\n",
        "    optimization_level=0, backend=backend, seed_transpiler=777\n",
        ")\n",
        "pm2 = generate_preset_pass_manager(\n",
        "    optimization_level=2, backend=backend, seed_transpiler=777\n",
        ")\n",
        "circ0 = pm0.run(ghz_circ)\n",
        "circ2 = pm2.run(ghz_circ)\n",
        "print(\"optimization_level=0:\")\n",
        "display(circ0.draw(\"mpl\", idle_wires=False, fold=-1))\n",
        "print(\"optimization_level=2:\")\n",
        "display(circ2.draw(\"mpl\", idle_wires=False, fold=-1))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "acd14f8c",
      "metadata": {},
      "source": [
        "### 2.2 Exercise\n",
        "\n",
        "Try `optimization_level=1` as well and compare the resulting circuit with the above two. Try it by modifying the code above.\n",
        "\n",
        "**Solution:**\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "6e8389e1",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "optimization_level=1:\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/6e8389e1-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "pm1 = generate_preset_pass_manager(\n",
        "    optimization_level=1, backend=backend, seed_transpiler=777\n",
        ")\n",
        "circ1 = pm1.run(ghz_circ)\n",
        "print(\"optimization_level=1:\")\n",
        "display(circ1.draw(\"mpl\", idle_wires=False, fold=-1))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "641ec604",
      "metadata": {},
      "source": [
        "Run on a fake backend (noisy simulation). See Appendix 1 for how to run on a real backend.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "dfb1b0ad",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: 93a4ac70-e3ea-44ad-aea9-5045840c9076\n"
          ]
        }
      ],
      "source": [
        "# run the circuits on the fake backend (noisy simulator)\n",
        "sampler = Sampler(backend=backend)\n",
        "job = sampler.run([circ0, circ2], shots=10000)\n",
        "print(f\"Job ID: {job.job_id()}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "fde8d64b",
      "metadata": {},
      "outputs": [],
      "source": [
        "# get results\n",
        "result = job.result()\n",
        "unoptimized_result = result[0].data.meas.get_counts()\n",
        "optimized_result = result[1].data.meas.get_counts()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "5d344bb9",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/5d344bb9-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 11,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.visualization import plot_histogram\n",
        "\n",
        "# plot\n",
        "sim_result = {\"0\" * 5: 0.5, \"1\" * 5: 0.5}\n",
        "plot_histogram(\n",
        "    [result for result in [sim_result, unoptimized_result, optimized_result]],\n",
        "    bar_labels=False,\n",
        "    legend=[\n",
        "        \"ideal\",\n",
        "        \"no optimization\",\n",
        "        \"with optimization\",\n",
        "    ],\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f6998d1e",
      "metadata": {},
      "source": [
        "## 3. Circuit synthesis matters\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1f6208e0",
      "metadata": {},
      "source": [
        "We next compare the results of running two differently synthesized 5-qubit GHZ state ($\\frac{1}{\\sqrt{2}} \\left( |00000\\rangle + |11111\\rangle \\right)$) preparation circuits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "896dc520",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/896dc520-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Original GHZ circuit (naive synthesis)\n",
        "ghz_circ.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "d27a9d9b",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/d27a9d9b-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# A cleverly-synthesized GHZ circuit\n",
        "ghz_circ2 = QuantumCircuit(5)\n",
        "ghz_circ2.h(2)\n",
        "ghz_circ2.cx(2, 1)\n",
        "ghz_circ2.cx(2, 3)\n",
        "ghz_circ2.cx(1, 0)\n",
        "ghz_circ2.cx(3, 4)\n",
        "ghz_circ2.measure_all()\n",
        "ghz_circ2.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "d4e16053",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "original synthesis:\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/d4e16053-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "new synthesis:\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/d4e16053-3.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# transpile both with the same optimization level 2\n",
        "circ_org = pm2.run(ghz_circ)\n",
        "circ_new = pm2.run(ghz_circ2)\n",
        "print(\"original synthesis:\")\n",
        "display(circ_org.draw(\"mpl\", idle_wires=False, fold=-1))\n",
        "print(\"new synthesis:\")\n",
        "display(circ_new.draw(\"mpl\", idle_wires=False, fold=-1))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "da0dbc8f",
      "metadata": {},
      "source": [
        "The new synthesis produces a shallower circuit. Why?\n",
        "\n",
        "This is because the new circuit can be laid out on linearly connected qubits, so on IBM® Brisbane's heavy-hexagon coupling graph as well, while the original circuit requires star-shaped connectivity (a degree-4 node) and hence cannot be laid out on the heavy-hex coupling graph, which has nodes at most degree 3. As a result, the original circuit requires qubit routing that adds SWAP gates, increasing the gate count.\n",
        "\n",
        "What we have done in the new circuit can be seen as a manual \"coupling constraint-aware\" circuit synthesis. In other words: manually solving circuit synthesis and circuit mapping at the same time.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "5f884bba",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: 19d635b0-4d8b-44c2-a76e-49e4b9078b1b\n"
          ]
        }
      ],
      "source": [
        "# run the circuits\n",
        "sampler = Sampler(backend=backend)\n",
        "job = sampler.run([circ_org, circ_new], shots=10000)\n",
        "print(f\"Job ID: {job.job_id()}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "3af5e682",
      "metadata": {},
      "outputs": [],
      "source": [
        "# get results\n",
        "result = job.result()\n",
        "synthesis_org_result = result[0].data.meas.get_counts()\n",
        "synthesis_new_result = result[1].data.meas.get_counts()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "80f8ef81",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/80f8ef81-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 17,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# plot\n",
        "sim_result = {\"0\" * 5: 0.5, \"1\" * 5: 0.5}\n",
        "plot_histogram(\n",
        "    [\n",
        "        result\n",
        "        for result in [\n",
        "            sim_result,\n",
        "            unoptimized_result,\n",
        "            synthesis_org_result,\n",
        "            synthesis_new_result,\n",
        "        ]\n",
        "    ],\n",
        "    bar_labels=False,\n",
        "    legend=[\n",
        "        \"ideal\",\n",
        "        \"no optimization\",\n",
        "        \"synthesis_org\",\n",
        "        \"synthesis_new\",\n",
        "    ],\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "96746945",
      "metadata": {},
      "source": [
        "In general, circuit synthesis depends on application and it's too difficult for a software to cover all possible applications. Qiskit transpiler happens to have no functions of synthesizing GHZ state preparation circuit. In such a case, manual circuit synthesis as shown above is worth considering.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "73844ec5",
      "metadata": {},
      "source": [
        "In this section, we look into the details of how Qiskit transpiler works using the following toy example circuit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f2228937",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/f2228937-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 18,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Build a toy example circuit\n",
        "from math import pi\n",
        "import itertools\n",
        "from qiskit.circuit import QuantumCircuit\n",
        "from qiskit.circuit.library import excitation_preserving\n",
        "\n",
        "circuit = QuantumCircuit(4, name=\"Example circuit\")\n",
        "circuit.append(excitation_preserving(4, reps=1, flatten=True), range(4))\n",
        "circuit.measure_all()\n",
        "\n",
        "value_cycle = itertools.cycle([0, pi / 4, pi / 2, 3 * pi / 4, pi, 2 * pi])\n",
        "circuit.assign_parameters(\n",
        "    [x[1] for x in zip(range(len(circuit.parameters)), value_cycle)], inplace=True\n",
        ")\n",
        "circuit.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "aacd9748",
      "metadata": {},
      "source": [
        "### 3.1 Draw the entire Qiskit transpilation flow\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c5e8511a",
      "metadata": {},
      "source": [
        "We look into the transpiler passes (tasks) for `optimization_level=1`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "74bd20af",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/74bd20af-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 19,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "# There is no need to read this entire image, but this outputs all the steps in the transpile() call\n",
        "# for optimization level 1\n",
        "pm = generate_preset_pass_manager(1, backend, seed_transpiler=42)\n",
        "pm.draw()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "833a8bcc",
      "metadata": {},
      "source": [
        "The flow consists of six stages:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "f58a6711",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "('init', 'layout', 'routing', 'translation', 'optimization', 'scheduling')\n"
          ]
        }
      ],
      "source": [
        "print(pm.stages)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f34ba488-1f4a-429e-8c1c-3b623ae4826c",
      "metadata": {
        "editable": true,
        "slideshow": {
          "slide_type": "slide"
        },
        "tags": []
      },
      "source": [
        "### 3.2 Draw an individual stage\n",
        "\n",
        "First, let's draw all the tasks (transpiler passes) done in the `init` stage.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "09b4ffbe",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/09b4ffbe-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 21,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm.init.draw()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e7e4329f",
      "metadata": {},
      "source": [
        "We can run each individual stage. Let's run `init` stage for our circuit. By enabling logger, we can see the details of the run.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "a139da85-e5b4-4c7c-900f-da8a0b8a5989",
      "metadata": {
        "editable": true,
        "slideshow": {
          "slide_type": "subslide"
        },
        "tags": []
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "INFO:qiskit.passmanager.base_tasks:Pass: UnitarySynthesis - 0.03576 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: HighLevelSynthesis - 0.16618 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: BasisTranslator - 0.07176 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: InverseCancellation - 0.27299 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: ContractIdleWiresInControlFlow - 0.00811 (ms)\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/a139da85-e5b4-4c7c-900f-da8a0b8a5989-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 22,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import logging\n",
        "\n",
        "logger = logging.getLogger()\n",
        "logger.setLevel(\"INFO\")\n",
        "\n",
        "init_out = pm.init.run(circuit)\n",
        "init_out.draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c97816d8",
      "metadata": {},
      "source": [
        "### 3.3 Exercise\n",
        "\n",
        "Draw `layout` stage passes and run the stage for the output circuit of the `init` stage (`init_out`), by modifying cells used above.\n",
        "\n",
        "**Solution:**\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "56024db6",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/56024db6-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "INFO:qiskit.passmanager.base_tasks:Pass: SetLayout - 0.01001 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: TrivialLayout - 0.07129 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: CheckMap - 0.08917 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: VF2Layout - 1.24431 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: BarrierBeforeFinalMeasurements - 0.02599 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: SabreLayout - 5.11169 (ms)\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/56024db6-2.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 23,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "display(pm.layout.draw())\n",
        "layout_out = pm.layout.run(init_out)\n",
        "layout_out.draw(\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6db6618a",
      "metadata": {},
      "source": [
        "Do the same thing for `translation` stage.\n",
        "\n",
        "**Solution:**\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "fd7cec6b",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/fd7cec6b-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "INFO:qiskit.passmanager.base_tasks:Pass: UnitarySynthesis - 0.03386 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: HighLevelSynthesis - 0.02718 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: BasisTranslator - 2.64192 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: CheckGateDirection - 0.02217 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: GateDirection - 0.36502 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: BasisTranslator - 0.64778 (ms)\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/fd7cec6b-2.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 24,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "display(pm.translation.draw())\n",
        "basis_out = pm.translation.run(layout_out)\n",
        "basis_out.draw(\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e3d78127-46f4-498a-958b-7c8ba107ae9d",
      "metadata": {
        "editable": true,
        "slideshow": {
          "slide_type": "slide"
        },
        "tags": []
      },
      "source": [
        "Note: Any individual stage cannot always be run independently (as some of them need to carry over information from one previous stage).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ff7370b9-6588-49c0-b82f-dbef823a973c",
      "metadata": {
        "editable": true,
        "slideshow": {
          "slide_type": "slide"
        },
        "tags": []
      },
      "source": [
        "### 3.4 Optimization Stage\n",
        "\n",
        "The last default stage in the pipeline is optimization. After we've embedded the circuit for the target the circuit has expanded quite a bit. Most of this is due to inefficiencies in the equivalence relationships from basis translation and swap insertion. The optimization stage is used to try and minimize the size and depth of the circuit. It runs a series of passes in a `do while` loop until it reaches a steady output.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "f86b9045",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/f86b9045-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 25,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# pm.pre_optimization.draw()\n",
        "pm.optimization.draw()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "c2ee9c96-b595-4882-a581-1dbd28ac980e",
      "metadata": {
        "editable": true,
        "slideshow": {
          "slide_type": "subslide"
        },
        "tags": []
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "INFO:qiskit.passmanager.base_tasks:Pass: Depth - 0.30112 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.03195 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: Size - 0.01216 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.01001 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: Optimize1qGatesDecomposition - 0.63729 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: InverseCancellation - 0.41723 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: ContractIdleWiresInControlFlow - 0.01192 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: GatesInBasis - 0.05484 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: Depth - 0.08583 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.20599 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: Size - 0.00787 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.00715 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: Optimize1qGatesDecomposition - 0.16809 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: InverseCancellation - 0.17190 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: ContractIdleWiresInControlFlow - 0.00691 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: GatesInBasis - 0.02408 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: Depth - 0.04935 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.00525 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: Size - 0.00620 (ms)\n",
            "INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.00286 (ms)\n"
          ]
        }
      ],
      "source": [
        "logger = logging.getLogger()\n",
        "logger.setLevel(\"INFO\")\n",
        "opt_out = pm.optimization.run(basis_out)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 28,
      "id": "65d650b0-ec27-4b1b-a121-f1bb958b18e2",
      "metadata": {
        "editable": true,
        "slideshow": {
          "slide_type": ""
        },
        "tags": []
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/65d650b0-ec27-4b1b-a121-f1bb958b18e2-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 28,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "opt_out.draw(\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "24c2abce-393a-41c5-9d1d-6273ad94a707",
      "metadata": {
        "editable": true,
        "slideshow": {
          "slide_type": "subslide"
        },
        "tags": []
      },
      "source": [
        "## 4. In-depth examples\n",
        "\n",
        "### 4.1 Two-qubit block optimization using two-qubit unitary synthesis\n",
        "\n",
        "For level 2 and 3, we have more passes (`Collect2qBlocks`, `ConsolidateBlocks`, `UnitarySynthesis`) for more optimization, namely two-qubit block optimization. (Compare the optimization stage flow for level 2 with that above for level 1)\n",
        "\n",
        "The two-qubit block optimization is composed of two steps: Collecting and consolidating 2-qubit blocks and synthesizing the 2-qubit unitary matrices.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "id": "179b1440",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/179b1440-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 29,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm2 = generate_preset_pass_manager(2, backend, seed_transpiler=42)\n",
        "pm2.optimization.draw()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "id": "e3f9e358-cc38-46cc-b2f7-f3bb9b9b179d",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.transpiler import PassManager\n",
        "from qiskit.transpiler.passes import (\n",
        "    Collect2qBlocks,\n",
        "    ConsolidateBlocks,\n",
        "    UnitarySynthesis,\n",
        ")\n",
        "\n",
        "# Collect 2q blocks and consolidate to unitary when we expect that we can reduce the 2q gate count for that unitary\n",
        "consolidate_pm = PassManager(\n",
        "    [\n",
        "        Collect2qBlocks(),\n",
        "        ConsolidateBlocks(target=backend.target),\n",
        "    ]\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "id": "bbf4fa9a-6b49-4833-82fd-b3821f6bcb78",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/bbf4fa9a-6b49-4833-82fd-b3821f6bcb78-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/bbf4fa9a-6b49-4833-82fd-b3821f6bcb78-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 36,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "display(basis_out.draw(\"mpl\", idle_wires=False, fold=-1))\n",
        "\n",
        "consolidated = consolidate_pm.run(basis_out)\n",
        "consolidated.draw(\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 37,
      "id": "7e7e0d3b-d267-4b1c-b207-42556d1ff3f2",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/7e7e0d3b-d267-4b1c-b207-42556d1ff3f2-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 37,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Synthesize unitaries\n",
        "UnitarySynthesis(target=backend.target)(consolidated).draw(\n",
        "    \"mpl\", idle_wires=False, fold=-1\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 38,
      "id": "a5c6dcec",
      "metadata": {},
      "outputs": [],
      "source": [
        "logger.setLevel(\"WARNING\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "59a51954-c737-4ee2-b1be-fee896388c83",
      "metadata": {},
      "source": [
        "We saw in Part 2 that the real quantum compiler flow is not that simple and is composed of many passes (tasks). This is mainly due to the software engineering required to ensure performance for a wide range of application circuits and maintainability of the software. Qiskit transpiler would work well in most cases but if you happen to see your circuit is not well optimized by Qiskit transpiler, it would be a good opportunity to research your own application-specific circuit optimization as shown in Part 1. Transpiler technology is evolving, your R\\&D contribution is welcome.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 39,
      "id": "86452399",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.circuit import QuantumCircuit\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, Sampler"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1ff499b3",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.backend(\"ibm_brisbane\")\n",
        "sampler = Sampler(backend)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 43,
      "id": "30a84ca1",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/30a84ca1-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 43,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "circ = QuantumCircuit(3)\n",
        "circ.ccx(0, 1, 2)\n",
        "circ.measure_all()\n",
        "circ.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 44,
      "id": "f58d9cb9",
      "metadata": {},
      "outputs": [
        {
          "ename": "IBMInputValueError",
          "evalue": "'The instruction ccx on qubits (0, 1, 2) is not supported by the target system. Circuits that do not match the target hardware definition are no longer supported after March 4, 2024. See the transpilation documentation (/docs/guides/transpile) for instructions to transform circuits and the primitive examples (/docs/guides/primitives-examples) to see this coupled with operator transformations.'",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
            "\u001b[31mIBMInputValueError\u001b[39m                        Traceback (most recent call last)",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[44]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[43msampler\u001b[49m\u001b[43m.\u001b[49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43mcirc\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m  \u001b[38;5;66;03m# IBMInputValueError will be raised\u001b[39;00m\n",
            "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/doc/lib/python3.11/site-packages/qiskit_ibm_runtime/sampler.py:111\u001b[39m, in \u001b[36mSamplerV2.run\u001b[39m\u001b[34m(self, pubs, shots)\u001b[39m\n\u001b[32m    107\u001b[39m coerced_pubs = [SamplerPub.coerce(pub, shots) \u001b[38;5;28;01mfor\u001b[39;00m pub \u001b[38;5;129;01min\u001b[39;00m pubs]\n\u001b[32m    109\u001b[39m validate_classical_registers(coerced_pubs)\n\u001b[32m--> \u001b[39m\u001b[32m111\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_run\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcoerced_pubs\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/doc/lib/python3.11/site-packages/qiskit_ibm_runtime/base_primitive.py:158\u001b[39m, in \u001b[36mBasePrimitiveV2._run\u001b[39m\u001b[34m(self, pubs)\u001b[39m\n\u001b[32m    156\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m pub \u001b[38;5;129;01min\u001b[39;00m pubs:\n\u001b[32m    157\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(\u001b[38;5;28mself\u001b[39m._backend, \u001b[33m\"\u001b[39m\u001b[33mtarget\u001b[39m\u001b[33m\"\u001b[39m, \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m is_simulator(\u001b[38;5;28mself\u001b[39m._backend):\n\u001b[32m--> \u001b[39m\u001b[32m158\u001b[39m         \u001b[43mvalidate_isa_circuits\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43mpub\u001b[49m\u001b[43m.\u001b[49m\u001b[43mcircuit\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_backend\u001b[49m\u001b[43m.\u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    160\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m._backend, IBMBackend):\n\u001b[32m    161\u001b[39m         \u001b[38;5;28mself\u001b[39m._backend.check_faulty(pub.circuit)\n",
            "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/doc/lib/python3.11/site-packages/qiskit_ibm_runtime/utils/validations.py:96\u001b[39m, in \u001b[36mvalidate_isa_circuits\u001b[39m\u001b[34m(circuits, target)\u001b[39m\n\u001b[32m     94\u001b[39m message = is_isa_circuit(circuit, target)\n\u001b[32m     95\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m message:\n\u001b[32m---> \u001b[39m\u001b[32m96\u001b[39m     \u001b[38;5;28;01mraise\u001b[39;00m IBMInputValueError(\n\u001b[32m     97\u001b[39m         message\n\u001b[32m     98\u001b[39m         + \u001b[33m\"\u001b[39m\u001b[33m Circuits that do not match the target hardware definition are no longer \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m     99\u001b[39m         \u001b[33m\"\u001b[39m\u001b[33msupported after March 4, 2024. See the transpilation documentation \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m    100\u001b[39m         \u001b[33m\"\u001b[39m\u001b[33m(https://quantum.cloud.ibm.com/docs/guides/transpile) for instructions \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m    101\u001b[39m         \u001b[33m\"\u001b[39m\u001b[33mto transform circuits and the primitive examples \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m    102\u001b[39m         \u001b[33m\"\u001b[39m\u001b[33m(https://quantum.cloud.ibm.com/docs/guides/primitives-examples) to see \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m    103\u001b[39m         \u001b[33m\"\u001b[39m\u001b[33mthis coupled with operator transformations.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m    104\u001b[39m     )\n",
            "\u001b[31mIBMInputValueError\u001b[39m: 'The instruction ccx on qubits (0, 1, 2) is not supported by the target system. Circuits that do not match the target hardware definition are no longer supported after March 4, 2024. See the transpilation documentation (https://quantum.cloud.ibm.com/docs/guides/transpile) for instructions to transform circuits and the primitive examples (https://quantum.cloud.ibm.com/docs/guides/primitives-examples) to see this coupled with operator transformations.'"
          ]
        }
      ],
      "source": [
        "sampler.run([circ])  # IBMInputValueError will be raised"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2a261d51",
      "metadata": {},
      "source": [
        "### 4.2 Circuit optimization matters\n",
        "\n",
        "We first compare the results of running 5-qubit GHZ state ($\\frac{1}{\\sqrt{2}} \\left( |00000\\rangle + |11111\\rangle \\right)$) preparation circuits with and without optimization.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 45,
      "id": "9483b736",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.circuit import QuantumCircuit\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, Sampler"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "52e99762",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "270db9aa",
      "metadata": {},
      "outputs": [],
      "source": [
        "# backend = service.backend('ibm_brisbane')\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")  # Eagle\n",
        "backend"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "29d29a39",
      "metadata": {},
      "source": [
        "We first use a GHZ circuit naively synthesized as follows.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 55,
      "id": "485b8ce6",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/485b8ce6-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 55,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "num_qubits = 5\n",
        "\n",
        "ghz_circ = QuantumCircuit(num_qubits)\n",
        "ghz_circ.h(0)\n",
        "[ghz_circ.cx(0, i) for i in range(1, num_qubits)]\n",
        "ghz_circ.measure_all()\n",
        "ghz_circ.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8eaa552e",
      "metadata": {},
      "source": [
        "We transpile the circuit without optimization (`optimization_level=0`) and with optimization (`optimization_level=2`).\n",
        "As you can see, there is a big difference in the circuit length of transpiled circuits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 56,
      "id": "87b861e2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "optimization_level=0:\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/87b861e2-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "optimization_level=2:\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/87b861e2-3.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "pm0 = generate_preset_pass_manager(\n",
        "    optimization_level=0, backend=backend, seed_transpiler=777\n",
        ")\n",
        "pm2 = generate_preset_pass_manager(\n",
        "    optimization_level=2, backend=backend, seed_transpiler=777\n",
        ")\n",
        "circ0 = pm0.run(ghz_circ)\n",
        "circ2 = pm2.run(ghz_circ)\n",
        "print(\"optimization_level=0:\")\n",
        "display(circ0.draw(\"mpl\", idle_wires=False, fold=-1))\n",
        "print(\"optimization_level=2:\")\n",
        "display(circ2.draw(\"mpl\", idle_wires=False, fold=-1))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 57,
      "id": "328f71f2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: d13rnnemya70008ek1zg\n"
          ]
        }
      ],
      "source": [
        "# run the circuits\n",
        "sampler = Sampler(backend)\n",
        "job = sampler.run([circ0, circ2], shots=10000)\n",
        "job_id = job.job_id()\n",
        "print(f\"Job ID: {job_id}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 58,
      "id": "d138e1e9",
      "metadata": {},
      "outputs": [],
      "source": [
        "# REPLACE WITH YOUR OWN JOB IDS\n",
        "job = service.job(job_id)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 59,
      "id": "c137e06a",
      "metadata": {},
      "outputs": [],
      "source": [
        "# get results\n",
        "result = job.result()\n",
        "unoptimized_result = result[0].data.meas.get_counts()\n",
        "optimized_result = result[1].data.meas.get_counts()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 60,
      "id": "7527976e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/7527976e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 60,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.visualization import plot_histogram\n",
        "\n",
        "# plot\n",
        "sim_result = {\"0\" * 5: 0.5, \"1\" * 5: 0.5}\n",
        "plot_histogram(\n",
        "    [result for result in [sim_result, unoptimized_result, optimized_result]],\n",
        "    bar_labels=False,\n",
        "    legend=[\n",
        "        \"ideal\",\n",
        "        \"no optimization\",\n",
        "        \"with optimization\",\n",
        "    ],\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d0d49ab7",
      "metadata": {},
      "source": [
        "### 4.3 Circuit synthesis matters\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c6643c6d",
      "metadata": {},
      "source": [
        "We next compare the results of running two differently synthesized 5-qubit GHZ state ($\\frac{1}{\\sqrt{2}} \\left( |00000\\rangle + |11111\\rangle \\right)$) preparation circuits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 61,
      "id": "886d9b45",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/886d9b45-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 61,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Original GHZ circuit (naive synthesis)\n",
        "ghz_circ.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 62,
      "id": "3b559186",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/3b559186-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 62,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# A better GHZ circuit (smarter synthesis), you learned in a previous lecture\n",
        "ghz_circ2 = QuantumCircuit(5)\n",
        "ghz_circ2.h(2)\n",
        "ghz_circ2.cx(2, 1)\n",
        "ghz_circ2.cx(2, 3)\n",
        "ghz_circ2.cx(1, 0)\n",
        "ghz_circ2.cx(3, 4)\n",
        "ghz_circ2.measure_all()\n",
        "ghz_circ2.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 63,
      "id": "054890b6",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "original synthesis:\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/054890b6-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "new synthesis:\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/054890b6-3.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "circ_org = pm2.run(ghz_circ)\n",
        "circ_new = pm2.run(ghz_circ2)\n",
        "print(\"original synthesis:\")\n",
        "display(circ_org.draw(\"mpl\", idle_wires=False, fold=-1))\n",
        "print(\"new synthesis:\")\n",
        "display(circ_new.draw(\"mpl\", idle_wires=False, fold=-1))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 64,
      "id": "de0c8577",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: d13rp283grvg008j12fg\n"
          ]
        }
      ],
      "source": [
        "# run the circuits\n",
        "sampler = Sampler(backend)\n",
        "job = sampler.run([circ_org, circ_new], shots=10000)\n",
        "job_id = job.job_id()\n",
        "print(f\"Job ID: {job_id}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 66,
      "id": "a6fcb968",
      "metadata": {},
      "outputs": [],
      "source": [
        "# REPLACE WITH YOUR OWN JOB IDS\n",
        "job = service.job(job_id)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 67,
      "id": "82165302",
      "metadata": {},
      "outputs": [],
      "source": [
        "# get results\n",
        "result = job.result()\n",
        "synthesis_org_result = result[0].data.meas.get_counts()\n",
        "synthesis_new_result = result[1].data.meas.get_counts()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 68,
      "id": "b9021da5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/b9021da5-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 68,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# plot\n",
        "sim_result = {\"0\" * 5: 0.5, \"1\" * 5: 0.5}\n",
        "plot_histogram(\n",
        "    [result for result in [sim_result, synthesis_org_result, synthesis_new_result]],\n",
        "    bar_labels=False,\n",
        "    legend=[\n",
        "        \"ideal\",\n",
        "        \"synthesis_org\",\n",
        "        \"synthesis_new\",\n",
        "    ],\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "07f7638d",
      "metadata": {},
      "source": [
        "### 4.4 General 1-qubit gate decomposition\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 69,
      "id": "f08c76bb",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit import QuantumCircuit, transpile\n",
        "from qiskit.circuit import Parameter\n",
        "from qiskit.circuit.library.standard_gates import UGate\n",
        "\n",
        "phi, theta, lam = Parameter(\"φ\"), Parameter(\"θ\"), Parameter(\"λ\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 70,
      "id": "ed93f69a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/ed93f69a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 70,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(1)\n",
        "qc.append(UGate(theta, phi, lam), [0])\n",
        "qc.draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 42,
      "id": "2fa17bd2",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/2fa17bd2-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 42,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "transpile(qc, basis_gates=[\"rz\", \"sx\"]).draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d8af1753",
      "metadata": {},
      "source": [
        "### 4.5 One-qubit block optimization\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 71,
      "id": "6f64d07d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/6f64d07d-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 71,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "\n",
        "qc = QuantumCircuit(1)\n",
        "qc.x(0)\n",
        "qc.y(0)\n",
        "qc.z(0)\n",
        "qc.rx(1.23, 0)\n",
        "qc.ry(1.23, 0)\n",
        "qc.rz(1.23, 0)\n",
        "qc.h(0)\n",
        "qc.s(0)\n",
        "qc.t(0)\n",
        "qc.sx(0)\n",
        "qc.sdg(0)\n",
        "qc.tdg(0)\n",
        "qc.draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 72,
      "id": "0aa1b908",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Operator([[ 0.45292511-0.57266982j, -0.66852684-0.14135058j],\n",
            "          [ 0.14135058+0.66852684j, -0.57266982+0.45292511j]],\n",
            "         input_dims=(2,), output_dims=(2,))\n"
          ]
        }
      ],
      "source": [
        "from qiskit.quantum_info import Operator\n",
        "\n",
        "Operator(qc)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 73,
      "id": "c06f5e75",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/c06f5e75-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 73,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit import transpile\n",
        "\n",
        "qc_opt = transpile(qc, basis_gates=[\"rz\", \"sx\"])\n",
        "qc_opt.draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 74,
      "id": "a9ec0568",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Operator([[ 0.45292511-0.57266982j, -0.66852684-0.14135058j],\n",
            "          [ 0.14135058+0.66852684j, -0.57266982+0.45292511j]],\n",
            "         input_dims=(2,), output_dims=(2,))\n"
          ]
        }
      ],
      "source": [
        "Operator(qc_opt)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 75,
      "id": "e83779af",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "True"
            ]
          },
          "execution_count": 75,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Operator(qc).equiv(Operator(qc_opt))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1ebdc297",
      "metadata": {},
      "source": [
        "### 4.6 Toffoli decomposition\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 76,
      "id": "f802c5df",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/f802c5df-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 76,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(3)\n",
        "qc.ccx(0, 1, 2)\n",
        "qc.draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 77,
      "id": "330cea7e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/330cea7e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 77,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit import QuantumCircuit, transpile\n",
        "\n",
        "qc = QuantumCircuit(3)\n",
        "qc.ccx(0, 1, 2)\n",
        "qc = transpile(qc, basis_gates=[\"rz\", \"sx\", \"cx\"])\n",
        "qc.draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "24004df8",
      "metadata": {},
      "source": [
        "### 4.7 CU gate decomposition\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 78,
      "id": "1df5876d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/1df5876d-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 78,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.circuit.library.standard_gates import CUGate\n",
        "\n",
        "phi, theta, lam, gamma = Parameter(\"φ\"), Parameter(\"θ\"), Parameter(\"λ\"), Parameter(\"γ\")\n",
        "qc = QuantumCircuit(2)\n",
        "# qc.cu(theta, phi, lam, gamma, 0, 1)\n",
        "qc.append(CUGate(theta, phi, lam, gamma), [0, 1])\n",
        "qc.draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 79,
      "id": "64f7e5f3",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/64f7e5f3-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 79,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.circuit.library.standard_gates import CUGate\n",
        "\n",
        "phi, theta, lam, gamma = Parameter(\"φ\"), Parameter(\"θ\"), Parameter(\"λ\"), Parameter(\"γ\")\n",
        "qc = QuantumCircuit(2)\n",
        "qc.append(CUGate(theta, phi, lam, gamma), [0, 1])\n",
        "qc = transpile(qc, basis_gates=[\"rz\", \"sx\", \"cx\"])\n",
        "qc.draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "88e7a028",
      "metadata": {},
      "source": [
        "### 4.8 CX, ECR, CZ equal up to local Cliffords\n",
        "\n",
        "Note that $H$(Hadamard), $S$($\\pi/2$ Z-rotation), $S^\\dagger$($-\\pi/2$ Z-rotation), $X$(Pauli X) are all Clifford gates.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 80,
      "id": "f5b362b6",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/f5b362b6-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 80,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(2)\n",
        "qc.cx(0, 1)\n",
        "qc.draw(output=\"mpl\", style=\"bw\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 81,
      "id": "8740d07b",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/8740d07b-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 81,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(2)\n",
        "qc.cx(0, 1)\n",
        "transpile(qc, basis_gates=[\"x\", \"s\", \"h\", \"sdg\", \"ecr\"]).draw(output=\"mpl\", style=\"bw\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 82,
      "id": "5113a7c5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/5113a7c5-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 82,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(2)\n",
        "qc.cx(0, 1)\n",
        "transpile(qc, basis_gates=[\"h\", \"cz\"]).draw(output=\"mpl\", style=\"bw\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f19867b3",
      "metadata": {},
      "source": [
        "Using IBM backend 1q basis gates \"rz\", \"sx\" and \"x\".\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 83,
      "id": "9d9b54d4",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/9d9b54d4-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 83,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(2)\n",
        "qc.cx(0, 1)\n",
        "transpile(qc, basis_gates=[\"rz\", \"sx\", \"x\", \"ecr\"]).draw(output=\"mpl\", style=\"bw\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 84,
      "id": "c395cd24",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/quantum-circuit-optimization/extracted-outputs/c395cd24-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 84,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(2)\n",
        "qc.cx(0, 1)\n",
        "transpile(qc, basis_gates=[\"rz\", \"sx\", \"x\", \"cz\"]).draw(output=\"mpl\", style=\"bw\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 85,
      "id": "4eab683f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'2.0.2'"
            ]
          },
          "execution_count": 85,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Check Qiskit version\n",
        "import qiskit\n",
        "\n",
        "qiskit.__version__"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "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"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "state": {},
        "version_major": 2,
        "version_minor": 0
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}