{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "d082b5c4-2440-4c96-a6db-831590087fe1",
      "metadata": {
        "id": "d082b5c4-2440-4c96-a6db-831590087fe1"
      },
      "source": [
        "# Introduction\n",
        "This lab continues using the Qiskit Framework, but explores how to create equivalent circuits.\n",
        "\n",
        "In these exercises you will be given circuits that you will look for relationships between the gates in order to reorganize, and reduce in gate count, but ultimately still result in the same operation. This is an important step in quantum compilation, as current quantum computers have limited capacity, it is important to use as few gates as possible.\n",
        "\n",
        "For the following questions you will create Qiskit circuits to be submitted. There will be no empty circuits (no gates), if the circuit is empty, then you will receive no points.\n",
        "\n",
        "# Some helpful programming hints:\n",
        "Some helpful programming hints:\n",
        "\n",
        "- The line circuit.draw(), where circuit is your Qiskit circuit, will draw out the circuit so you can visualize it. This must be the final call in a cell in order for the circuit to be rendered, alternatively, you can call ```print(circuit)``` at any point to see an ascii representation of the circuit\n",
        "- op = qiskit.quantum_info.Operator(circuit) will create an operator object, and op.data will let you look at the overall matrix for a circuit.\n",
        "- Keep in mind that Qiskit has a different relationship between the drawing and mathematical representation than we have. Specifically, they place the left-most bit at the bottom rather than at the top. You can [**watch this video**](https://youtu.be/Gf7XFFKS9jE) for more information. This has several implications.\n",
        "- If you look at a circuit the way we do, then the state vector ends up being stored as \\[00, 10, 01, 11\\] rather than \\[00, 01, 10, 11\\] (where the qubit on top is still the left-most qubit).\n",
        "- In reality, though, Qiskit also considers the qubit order to be swapped (little endian), where the top qubit is the least significant (right-most) bit. That is for qubits from top to bottom q0, q1, q2, the bitstring is q2, q1, q0. So the state vector is still \\[00, 01, 10, 11\\] from this perspective. We can see this in the CX gate.\n",
        "\n",
        "```\n",
        "q0_0: ──■──  \n",
        "      ┌─┴─┐  \n",
        "q0_1: ┤ X ├  \n",
        "      └───┘  \n",
        "```\n",
        "   \n",
        "This ordering also affects the matrix, resulting in the following for CX:  \n",
        "```\n",
        "[[1, 0, 0, 0],  \n",
        " [0, 0, 0, 1],  \n",
        " [0, 0, 1, 0],  \n",
        " [0, 1, 0, 0]]  \n",
        "```\n",
        "\n",
        "Which will take \\[00: w, 01: x, 10: y, 11: z\\] to \\[00: w, 01: z, 10: y, 11: x\\] in little endian form, and \\[00: w, 01: y, 10: z, 11: x\\] in big endian form (most significant bit first).\n",
        "\n",
        "# Grading:  \n",
        "- The output matrix of your circuit will be compared against a baseline circuit, your circuit will be compared against this matrix.\n",
        "- If they do not match, we will test the circuit with different inputs and compare against the expected values.\n",
        "- You will receive feedback for whether the circuit runs. If it does not, you will receive an error message. If it runs with no message, it means that your circuit runs, but not necessarily that the answer is correct.\n",
        "- **Do not change any function names or return types**.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "9aLAWbN1L8BM",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "9aLAWbN1L8BM",
        "outputId": "be012b4f-e4ac-46af-f746-540de01e2333"
      },
      "outputs": [],
      "source": [
        "## RUN THIS CELL TO INSTALL QISKIT & OTHER RESOURCES\n",
        "## (Press Shift+Enter or click on ▶️)\n",
        "!pip install qiskit\n",
        "!pip install qiskit_ibm_runtime\n",
        "!pip install matplotlib\n",
        "!pip install pylatexenc\n",
        "!pip install qiskit-aer"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c6306750-3009-4377-82eb-8b9f6f6d6aa0",
      "metadata": {
        "id": "c6306750-3009-4377-82eb-8b9f6f6d6aa0"
      },
      "source": [
        "# Exercise 1: Decomposition and Cancellation\n",
        "```\n",
        "\n",
        "    ┌───┐          ┌───┐   ┌───┐\n",
        "q0: ┤ X ├──────────┤ X ├─X─┤ X ├\n",
        "    ├───┤┌───┐┌───┐└─┬─┘ │ └─┬─┘\n",
        "q1: ┤ H ├┤ X ├┤ H ├──■───X───■──\n",
        "    └───┘└───┘└───┘  \n",
        "      \n",
        "```\n",
        "Recreate the above circuit, using less gates. Examine how different gates can be broken up, and reorganized, to use less gates overall. It may be helpful to think of how the circuit would transform a given state $\\alpha \\ket{00} + \\beta \\ket{01} + \\gamma \\ket{10} + \\delta \\ket{11}$, and make sure that both circuits perform the same operation.\n",
        "\n",
        "You may include helper functions if needed.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "b3547fb9-1733-43a7-86d0-fb146bf0ded6",
      "metadata": {
        "id": "b3547fb9-1733-43a7-86d0-fb146bf0ded6"
      },
      "outputs": [],
      "source": [
        "import qiskit\n",
        "\n",
        "def hw2_1_response():\n",
        "    qr1 = qiskit.QuantumRegister(2)\n",
        "    qc1 = qiskit.QuantumCircuit(qr1)\n",
        "\n",
        "    # Put your code here (spaces for indentation)\n",
        "    # End Code\n",
        "\n",
        "    return qc1\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5d7ca0ec-f348-4bb9-a0d5-fdb72182447b",
      "metadata": {
        "id": "5d7ca0ec-f348-4bb9-a0d5-fdb72182447b"
      },
      "source": [
        "# Exercise 2: Commutative Instructions\n",
        "```\n",
        "\n",
        "                   ┌───┐┌───┐┌───┐┌───┐┌───┐     ┌───┐\n",
        "q0: ──■─────────■──┤ Z ├┤ X ├┤ X ├┤ X ├┤ Z ├──■──┤ Z ├\n",
        "    ┌─┴─┐┌───┐┌─┴─┐├───┤├───┤└─┬─┘├───┤├───┤┌─┴─┐├───┤\n",
        "q1: ┤ X ├┤ H ├┤ X ├┤ X ├┤ Z ├──■──┤ Z ├┤ X ├┤ X ├┤ X ├\n",
        "    └───┘└───┘└───┘└───┘└───┘     └───┘└───┘└───┘└───┘\n",
        "      \n",
        "\n",
        "```\n",
        "Recreate the above circuit, using less gates. Examine how different gates can be flipped, to use less gates overall. It may be helpful to think of how the circuit would transform a given state $\\alpha \\ket{00} + \\beta \\ket{01} + \\gamma \\ket{10} + \\delta \\ket{11}$, and make sure that both circuits perform the same operation.\n",
        "\n",
        "You may include helper functions if needed."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "f11eca24-c641-4ff6-ae2c-4deef5c6e0b8",
      "metadata": {
        "id": "f11eca24-c641-4ff6-ae2c-4deef5c6e0b8"
      },
      "outputs": [],
      "source": [
        "import qiskit\n",
        "\n",
        "def hw2_2_response():\n",
        "    qr2 = qiskit.QuantumRegister(2)\n",
        "    qc2 = qiskit.QuantumCircuit(qr2)\n",
        "\n",
        "    # Put your code here (spaces for indentation)\n",
        "    # End Code\n",
        "\n",
        "    return qc2\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "96ecd534-4719-4515-9553-e8cd2350b1d7",
      "metadata": {
        "id": "96ecd534-4719-4515-9553-e8cd2350b1d7"
      },
      "source": [
        "# Exercise 3: Equivalent Composition\n",
        "```\n",
        "\n",
        "    ┌───┐┌───┐     ┌───┐                    ┌───┐\n",
        "q0: ┤ H ├┤ Z ├──■──┤ Z ├──■──────────────■──┤ H ├\n",
        "    └───┘└───┘┌─┴─┐└───┘┌─┴─┐            │  └───┘\n",
        "q1: ──────────┤ X ├──■──┤ X ├──■─────────┼───────\n",
        "              └───┘┌─┴─┐└───┘┌─┴─┐┌───┐┌─┴─┐     \n",
        "q2: ───────────────┤ X ├─────┤ X ├┤ X ├┤ X ├─────\n",
        "                   └───┘     └───┘└───┘└───┘     \n",
        "      \n",
        "\n",
        "```\n",
        "Recreate the above circuit, using less gates. Look at how you can combine gates to reorganize the circuit and use less gates overall. It may be helpful to think of how the circuit would transform a given state $\\alpha \\ket{000} + \\beta \\ket{001} + \\gamma \\ket{010} + \\delta \\ket{011} + w\\ket{100} + x\\ket{101} + y\\ket{110} + z\\ket{111}$, and make sure that both circuits perform the same operation.\n",
        "\n",
        "You may include helper functions if needed."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "f929240c-69cf-464a-88db-37ca1efdb087",
      "metadata": {
        "id": "f929240c-69cf-464a-88db-37ca1efdb087"
      },
      "outputs": [],
      "source": [
        "import qiskit\n",
        "\n",
        "def hw2_3_response():\n",
        "    qr3 = qiskit.QuantumRegister(3)\n",
        "    qc3 = qiskit.QuantumCircuit(qr3)\n",
        "\n",
        "    # Put your code here (spaces for indentation)\n",
        "    # End Code\n",
        "\n",
        "    return qc3\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "be419955-6efc-4ec8-bea9-117bc77dc244",
      "metadata": {
        "id": "be419955-6efc-4ec8-bea9-117bc77dc244",
        "jp-MarkdownHeadingCollapsed": true,
        "tags": []
      },
      "source": [
        "# Submission\n",
        "Congratulations on completing the lab! Make sure you:\n",
        "\n",
        "1. Test all of your functions by calling them at least once.\n",
        "2. Download your lab as a **Python** `.py` script (*not* an `.ipynb` file):\n",
        "\n",
        "    ```File -> Download -> Download .py```\n",
        "\n",
        "3. Rename the downloaded file to `Lab7Answers.py`.\n",
        "4. Upload `Lab7Answers.py` to Gradescope.\n",
        "5. Ensure the autograder runs successfully."
      ]
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Qiskit v0.34.2 (ipykernel)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.8.12"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
