{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "561e36c0-dca0-4493-b419-72cc5888325d",
      "metadata": {},
      "source": [
        "---\n",
        "title: Qiskit implementation\n",
        "description: Using Qiskit to implement ideas from the multiple-systems lesson.\n",
        "---\n",
        "\n",
        "# Qiskit implementation\n",
        "\n",
        "In the previous lesson, we took a first look at the `Statevector` and `Operator` classes in Qiskit, and used them to simulate operations and measurements on single qubits.\n",
        "In this section, we'll use these classes to explore the behavior of multiple qubits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "ccae3e0d-3195-469c-b398-00da485bb2b9",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2.1.1\n"
          ]
        }
      ],
      "source": [
        "from qiskit import __version__\n",
        "\n",
        "print(__version__)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3b988d90-43d5-42e0-bc67-ed9d292b86b9",
      "metadata": {},
      "source": [
        "We'll start by importing the `Statevector` and `Operator` classes, as well as the square root function from `NumPy`.\n",
        "Hereafter, generally speaking, we'll take care of all of our required imports first within each lesson.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "d38829a6",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.quantum_info import Statevector, Operator\n",
        "from numpy import sqrt"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b1eaeb43",
      "metadata": {},
      "source": [
        "## Tensor products\n",
        "\n",
        "The `Statevector` class has a `tensor` method, which returns the tensor product of that `Statevector` with another, given as an argument.\n",
        "The argument is interpreted as the tensor factor on the right.\n",
        "\n",
        "For example, below we create two state vectors representing $\\vert 0\\rangle$ and $\\vert 1\\rangle$, and use the `tensor` method to create a new vector, $\\vert \\psi\\rangle = \\vert 0\\rangle \\otimes \\vert 1\\rangle$.\n",
        "Notice here that we're using the `from_label` method to define the states $\\vert 0\\rangle$ and $\\vert 1\\rangle$, rather than defining them ourselves.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "da1a4b33",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/latex": [
              "$$ |01\\rangle$$"
            ],
            "text/plain": [
              "<IPython.core.display.Latex object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "zero = Statevector.from_label(\"0\")\n",
        "one = Statevector.from_label(\"1\")\n",
        "psi = zero.tensor(one)\n",
        "display(psi.draw(\"latex\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "60007f43-c890-4f03-8d38-37f8e08923fa",
      "metadata": {},
      "source": [
        "Other allowed labels include \"+\" and \"-\" for the plus and minus states, as well as \"r\" and \"l\" (short for \"right\" and \"left\") for the states\n",
        "\n",
        "$$\n",
        "\\vert {+i} \\rangle = \\frac{1}{\\sqrt{2}} \\vert 0 \\rangle + \\frac{i}{\\sqrt{2}} \\vert 1 \\rangle\n",
        "\\qquad\\text{and}\\qquad\n",
        "\\vert {-i} \\rangle = \\frac{1}{\\sqrt{2}} \\vert 0 \\rangle - \\frac{i}{\\sqrt{2}} \\vert 1 \\rangle.\n",
        "$$\n",
        "\n",
        "Here, \"+\", \"-\" or \"right\" and \"left\" come from the context of quantum mechanical spin, in which a component of spin may point to the left or the right in an experiment; it is not referring to the right-most or left-most qubit in systems of multiple qubits. Here's an example of the tensor product of $\\vert {+} \\rangle$ and $\\vert {-i} \\rangle$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "3bea1435",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/latex": [
              "$$\\frac{1}{2} |00\\rangle- \\frac{i}{2} |01\\rangle+\\frac{1}{2} |10\\rangle- \\frac{i}{2} |11\\rangle$$"
            ],
            "text/plain": [
              "<IPython.core.display.Latex object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plus = Statevector.from_label(\"+\")\n",
        "minus_i = Statevector.from_label(\"l\")\n",
        "phi = plus.tensor(minus_i)\n",
        "display(phi.draw(\"latex\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d00d7458-61da-4a4d-81b4-e57f66504d49",
      "metadata": {},
      "source": [
        "An alternative is to use the `^` operation for tensor products, which naturally gives the same results.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "c29b76c5-8513-4e8b-b95e-0fe91fa31986",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/latex": [
              "$$\\frac{1}{2} |00\\rangle- \\frac{i}{2} |01\\rangle+\\frac{1}{2} |10\\rangle- \\frac{i}{2} |11\\rangle$$"
            ],
            "text/plain": [
              "<IPython.core.display.Latex object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "display((plus ^ minus_i).draw(\"latex\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "25872adb",
      "metadata": {},
      "source": [
        "The `Operator` class also has a `tensor` method (as well as a `from_label` method), as we see in the following examples.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "3ca88116",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/latex": [
              "$$\n",
              "\n",
              "\\begin{bmatrix}\n",
              "\\frac{\\sqrt{2}}{2} & 0 & \\frac{\\sqrt{2}}{2} & 0  \\\\\n",
              " 0 & \\frac{\\sqrt{2}}{2} & 0 & \\frac{\\sqrt{2}}{2}  \\\\\n",
              " \\frac{\\sqrt{2}}{2} & 0 & - \\frac{\\sqrt{2}}{2} & 0  \\\\\n",
              " 0 & \\frac{\\sqrt{2}}{2} & 0 & - \\frac{\\sqrt{2}}{2}  \\\\\n",
              " \\end{bmatrix}\n",
              "$$"
            ],
            "text/plain": [
              "<IPython.core.display.Latex object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/latex": [
              "$$\n",
              "\n",
              "\\begin{bmatrix}\n",
              "0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & \\frac{\\sqrt{2}}{2} & 0 & 0  \\\\\n",
              " \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0  \\\\\n",
              " 0 & 0 & 0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & \\frac{\\sqrt{2}}{2}  \\\\\n",
              " 0 & 0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & \\frac{\\sqrt{2}}{2} & 0  \\\\\n",
              " 0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & - \\frac{\\sqrt{2}}{2} & 0 & 0  \\\\\n",
              " \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & - \\frac{\\sqrt{2}}{2} & 0 & 0 & 0  \\\\\n",
              " 0 & 0 & 0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & - \\frac{\\sqrt{2}}{2}  \\\\\n",
              " 0 & 0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & - \\frac{\\sqrt{2}}{2} & 0  \\\\\n",
              " \\end{bmatrix}\n",
              "$$"
            ],
            "text/plain": [
              "<IPython.core.display.Latex object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "H = Operator.from_label(\"H\")\n",
        "Id = Operator.from_label(\"I\")\n",
        "X = Operator.from_label(\"X\")\n",
        "display(H.tensor(Id).draw(\"latex\"))\n",
        "display(H.tensor(Id).tensor(X).draw(\"latex\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "45fbefaf-7144-4375-acc9-44bbdea46333",
      "metadata": {},
      "source": [
        "Again, like in the vector case, the `^` operation is equivalent.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "c43069b5-07be-4e7f-99c1-c3ddbd86b5c7",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/latex": [
              "$$\n",
              "\n",
              "\\begin{bmatrix}\n",
              "0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & \\frac{\\sqrt{2}}{2} & 0 & 0  \\\\\n",
              " \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0  \\\\\n",
              " 0 & 0 & 0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & \\frac{\\sqrt{2}}{2}  \\\\\n",
              " 0 & 0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & \\frac{\\sqrt{2}}{2} & 0  \\\\\n",
              " 0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & - \\frac{\\sqrt{2}}{2} & 0 & 0  \\\\\n",
              " \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & - \\frac{\\sqrt{2}}{2} & 0 & 0 & 0  \\\\\n",
              " 0 & 0 & 0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & - \\frac{\\sqrt{2}}{2}  \\\\\n",
              " 0 & 0 & \\frac{\\sqrt{2}}{2} & 0 & 0 & 0 & - \\frac{\\sqrt{2}}{2} & 0  \\\\\n",
              " \\end{bmatrix}\n",
              "$$"
            ],
            "text/plain": [
              "<IPython.core.display.Latex object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "display((H ^ Id ^ X).draw(\"latex\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5b149f91",
      "metadata": {},
      "source": [
        "Compound states can be evolved using compound operations as we would expect — just like we saw for single systems in the previous lesson.\n",
        "For example, the following code computes the state $(H\\otimes I)\\vert\\phi\\rangle$ for $\\vert\\phi\\rangle = \\vert + \\rangle \\otimes \\vert {-i}\\rangle$ (which was already defined above).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "850cb4ff",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/latex": [
              "$$\\frac{\\sqrt{2}}{2} |00\\rangle- \\frac{\\sqrt{2} i}{2} |01\\rangle$$"
            ],
            "text/plain": [
              "<IPython.core.display.Latex object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "display(phi.evolve(H ^ Id).draw(\"latex\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "933974bf",
      "metadata": {},
      "source": [
        "Here is some code that defines a $CX$ operation and calculates $CX \\vert\\psi\\rangle$ for $\\vert\\psi\\rangle = \\vert + \\rangle \\otimes \\vert 0 \\rangle$. To be clear, this is a $CX$ operation for which the left-hand qubit is the control and the right-hand qubit is the target. The result is the Bell state $\\vert\\phi^{+}\\rangle$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "dce9679d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/latex": [
              "$$\\frac{\\sqrt{2}}{2} |00\\rangle+\\frac{\\sqrt{2}}{2} |11\\rangle$$"
            ],
            "text/plain": [
              "<IPython.core.display.Latex object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "CX = Operator([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]])\n",
        "psi = plus.tensor(zero)\n",
        "display(psi.evolve(CX).draw(\"latex\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4e69bfe5-9533-4218-88bc-c59afdcdfec3",
      "metadata": {},
      "source": [
        "## Partial measurements\n",
        "\n",
        "In the previous lesson, we used the `measure` method to simulate a measurement of a quantum state vector.\n",
        "This method returns two items: the simulated measurement result, and the new `Statevector` given this measurement.\n",
        "\n",
        "By default, `measure` measures all qubits in the state vector.\n",
        "We can, alternatively, provide a list of integers as an argument, which causes only those qubit indices to be measured.\n",
        "To demonstrate this, the code below creates the state\n",
        "\n",
        "$$\n",
        "\\vert w\\rangle = \\frac{\\vert 001\\rangle + \\vert 010\\rangle + \\vert 100\\rangle}{\\sqrt{3}}\n",
        "$$\n",
        "\n",
        "and measures qubit number 0, which is the rightmost qubit.\n",
        "(Qiskit numbers qubits starting from 0, from right to left. We'll return to this numbering convention in the next lesson.)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "1e76a49f-fc55-4a48-bd56-d812ac59572b",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/latex": [
              "$$\\frac{\\sqrt{3}}{3} |001\\rangle+\\frac{\\sqrt{3}}{3} |010\\rangle+\\frac{\\sqrt{3}}{3} |100\\rangle$$"
            ],
            "text/plain": [
              "<IPython.core.display.Latex object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Measured: 0\n",
            "State after measurement:\n"
          ]
        },
        {
          "data": {
            "text/latex": [
              "$$\\frac{\\sqrt{2}}{2} |010\\rangle+\\frac{\\sqrt{2}}{2} |100\\rangle$$"
            ],
            "text/plain": [
              "<IPython.core.display.Latex object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Measured: 00\n",
            "State after measurement:\n"
          ]
        },
        {
          "data": {
            "text/latex": [
              "$$ |100\\rangle$$"
            ],
            "text/plain": [
              "<IPython.core.display.Latex object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "w = Statevector([0, 1, 1, 0, 1, 0, 0, 0] / sqrt(3))\n",
        "display(w.draw(\"latex\"))\n",
        "\n",
        "result, state = w.measure([0])\n",
        "print(f\"Measured: {result}\\nState after measurement:\")\n",
        "display(state.draw(\"latex\"))\n",
        "\n",
        "result, state = w.measure([0, 1])\n",
        "print(f\"Measured: {result}\\nState after measurement:\")\n",
        "display(state.draw(\"latex\"))"
      ]
    },
    {
      "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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}