{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Simulators\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Introduction\n",
        "\n",
        "This notebook shows how to import the *Qiskit Aer* simulator backend and use it to run ideal (noise free)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "id": "wDHGd5xNLlRp"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "\n",
        "# Import Qiskit\n",
        "from qiskit import QuantumCircuit, transpile\n",
        "from qiskit_aer import AerSimulator\n",
        "from qiskit.visualization import plot_histogram, plot_state_city\n",
        "import qiskit.quantum_info as qi"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "970GeWlQNsIq"
      },
      "source": [
        "## The AerSimulator\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "KtXOXfCXN41Z"
      },
      "source": [
        "\n",
        "1. `AerSimulator.available_devices()` : Return the available simulation devices.\n",
        "2. `AerSimulator.available_methods()` : Return the available simulation methods."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {
        "id": "ViBewmJRM_Kq"
      },
      "outputs": [],
      "source": [
        "simulator = AerSimulator()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TveWKXEOPRXg"
      },
      "source": [
        "## Simulating a Quantum Circuit\n",
        "\n",
        "The basic operation runs a quantum circuit and returns a counts dictionary of measurement outcomes. Here we run a simple circuit that prepares a 2-qubit Bell-state $\\left|\\psi\\right\\rangle = \\frac{1}{\\sqrt{2}}\\left(\\left|0,0\\right\\rangle + \\left|1,1 \\right\\rangle\\right)$\n",
        "and measures both qubits."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 483
        },
        "id": "FyfGD04tPOiZ",
        "outputId": "d6ec7079-116f-4651-cbb7-3920c5b5269c"
      },
      "outputs": [
        {
          "data": {
            "image/png": "[encoded data, 20116 characters]",
            "text/plain": [
              "<Figure size 700x500 with 1 Axes>"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Create circuit\n",
        "circ = QuantumCircuit(2)\n",
        "circ.h(0)\n",
        "circ.cx(0, 1)\n",
        "circ.measure_all()\n",
        "\n",
        "# Transpile for simulator\n",
        "simulator = AerSimulator()\n",
        "circ = transpile(circ, simulator)\n",
        "\n",
        "# Run and get counts\n",
        "result = simulator.run(circ).result()\n",
        "counts = result.get_counts(circ)\n",
        "plot_histogram(counts, title='Bell-State counts')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SkRarb0ePkdz"
      },
      "source": [
        "\n",
        "### Returning measurement outcomes for each shot\n",
        "\n",
        "The `Simulator` also supports returning a list of measurement outcomes for each individual shot. This is enabled by setting the keyword argument `memory=True` in the run.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Npve6RQKPntJ",
        "outputId": "25716d56-bf08-4934-cc19-e26bd82ac3b7"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "['11', '00', '11', '00', '00', '00', '00', '00', '11', '11']\n"
          ]
        }
      ],
      "source": [
        "# Run and get memory\n",
        "result = simulator.run(circ, shots=10, memory=True).result()\n",
        "memory = result.get_memory(circ)\n",
        "print(memory)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pEwPCts-Px8I"
      },
      "source": [
        "\n",
        "### Aer Simulator Options\n",
        "\n",
        "The `AerSimulator` backend supports a variety of configurable options which can be updated using the set_options method. See the AerSimulator API documentation for additional details.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Simulation Method\n",
        "\n",
        "The `AerSimulator` supports a variety of simulation methods, each of which supports a different set of instructions. The method can be set manually using `simulator(method=value)` option, or a simulator backend with a preconfigured method can be obtained directly from the `AerSimulator` \n",
        "\n",
        "When simulating ideal circuits, changing the method between the exact simulation methods `stabilizer`, `statevector`, `density_matrix` and `matrix_product_state` should not change the simulation result (other than usual variations from sampling probabilities for measurement outcomes)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Simulation Method Option\n",
        "\n",
        "The simulation method is set using the method kwarg. A list supported simulation methods can be returned using available_methods(), these are\n",
        "\n",
        "1.  `\"automatic\"`: Default simulation method. Select the simulation method automatically based on the circuit and noise model.\n",
        "\n",
        "2.  `\"statevector\"`: A dense statevector simulation that can sample measurement outcomes from ideal circuits with all measurements at end of the circuit. For noisy simulations each shot samples a randomly sampled noisy circuit from the noise model.\n",
        "    \n",
        "    \n",
        "3. `\"density_matrix\"`: A dense density matrix simulation that may sample measurement outcomes from noisy circuits with all measurements at end of the circuit.\n",
        "    \n",
        "4. `\"stabilizer\"`: An efficient Clifford stabilizer state simulator that can simulate noisy Clifford circuits if all errors in the noise model are also Clifford errors.\n",
        "    \n",
        "    \n",
        "5. `\"extended_stabilizer\"`: An approximate simulated for Clifford + T circuits based on a state decomposition into ranked-stabilizer state. The number of terms grows with the number of non-Clifford (T) gates.\n",
        "    \n",
        "    \n",
        "6. `\"matrix_product_state\"`: A tensor-network statevector simulator that uses a Matrix Product State (MPS) representation for the state. This can be done either with or without truncation of the MPS bond dimensions depending on the simulator options. The default behaviour is no truncation.\n",
        "    \n",
        "    \n",
        "7. `\"unitary\"`: A dense unitary matrix simulation of an ideal circuit. This simulates the unitary matrix of the circuit itself rather than the evolution of an initial quantum state. This method can only simulate gates, it does not support measurement, reset, or noise.\n",
        "    \n",
        "8.  `\"superop\"`: A dense superoperator matrix simulation of an ideal or noisy circuit. This simulates the superoperator matrix of the circuit itself rather than the evolution of an initial quantum state. This method can simulate ideal and noisy gates, and reset, but does not support measurement.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 483
        },
        "id": "L-Yf5GZhPo0p",
        "outputId": "c2e02960-1e87-4565-8b2d-c96a73cb4b90"
      },
      "outputs": [
        {
          "data": {
            "image/png": "[encoded data, 50820 characters]",
            "text/plain": [
              "<Figure size 700x500 with 1 Axes>"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Increase shots to reduce sampling variance\n",
        "shots = 10000\n",
        "\n",
        "\n",
        "\n",
        "# Statevector simulation method\n",
        "sim_statevector = AerSimulator(method='statevector')\n",
        "job_statevector = sim_statevector.run(circ, shots=shots)\n",
        "counts_statevector = job_statevector.result().get_counts(0)\n",
        "\n",
        "# Stabilizer simulation method\n",
        "sim_stabilizer = AerSimulator(method='stabilizer')\n",
        "job_stabilizer = sim_stabilizer.run(circ, shots=shots)\n",
        "counts_stabilizer = job_stabilizer.result().get_counts(0)\n",
        "\n",
        "\n",
        "# Extended Stabilizer method\n",
        "sim_extstabilizer = AerSimulator(method='extended_stabilizer')\n",
        "job_extstabilizer = sim_extstabilizer.run(circ, shots=shots)\n",
        "counts_extstabilizer = job_extstabilizer.result().get_counts(0)\n",
        "\n",
        "# Density Matrix simulation method\n",
        "sim_density = AerSimulator(method='density_matrix')\n",
        "job_density = sim_density.run(circ, shots=shots)\n",
        "counts_density = job_density.result().get_counts(0)\n",
        "\n",
        "# Matrix Product State simulation method\n",
        "sim_mps = AerSimulator(method='matrix_product_state')\n",
        "job_mps = sim_mps.run(circ, shots=shots)\n",
        "counts_mps = job_mps.result().get_counts(0)\n",
        "\n",
        "\n",
        "plot_histogram([ counts_statevector,counts_stabilizer ,counts_extstabilizer, counts_density, counts_mps],\n",
        "               title='Counts for different simulation methods',\n",
        "               legend=[ 'statevector',\n",
        "                       'density_matrix','stabilizer','extended_stabilizer', 'matrix_product_state'])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4YkWLUQbSdyD"
      },
      "source": [
        "\n",
        "#### Automatic Simulation Method\n",
        "\n",
        "The default simulation method is automatic which will automatically select a one of the other simulation methods for each circuit based on the instructions in those circuits. A fixed simulation method can be specified by by adding the method name when getting the backend, or by setting the method option on the backend.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 483
        },
        "id": "BEJqR-O1Rkss",
        "outputId": "8780440f-d13f-4432-852c-efccb4436b1a"
      },
      "outputs": [
        {
          "data": {
            "image/png": "[encoded data, 28676 characters]",
            "text/plain": [
              "<Figure size 700x500 with 1 Axes>"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "\n",
        "# automatic\n",
        "sim_automatic = AerSimulator(method='automatic')\n",
        "job_automatic = sim_automatic.run(circ, shots=shots)\n",
        "counts_automatic = job_automatic.result().get_counts(0)\n",
        "\n",
        "plot_histogram([counts_automatic], title='Counts for automatic simulation method',legend=[ 'automatic'])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FitzkDKPS3yZ"
      },
      "source": [
        "### GPU Simulation\n",
        "The `statevector`, `density_matrix` and `unitary` simulators support running on a NVidia GPUs. For these methods the simulation device can also be manually set to CPU or GPU using `simulator = AerSimmulator(method='statevector',device='GPU')` backend option.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {
        "id": "diCG8_tPSxLr"
      },
      "outputs": [],
      "source": [
        "from qiskit_aer import AerError\n",
        "\n",
        "# Initialize a GPU backend\n",
        "# Note that the cloud instance for tutorials does not have a GPU\n",
        "# so this will raise an exception.\n",
        "try:\n",
        "    simulator_gpu = AerSimulator(method='statevector', device='GPU')\n",
        "\n",
        "except AerError as e:\n",
        "    print(e)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "g0dn64qdTi3m"
      },
      "source": [
        "## Installing GPU Support\n",
        "\n",
        "In order to install and run the GPU supported simulators on Linux, you need CUDA® 11.2 or newer previously installed. CUDA® itself would require a set of specific GPU drivers. Please follow CUDA® installation procedure in the NVIDIA® [web](https://www.nvidia.com/drivers).\n",
        "\n",
        "If you want to install our GPU supported simulators, you have to install this other package:\n",
        "\n",
        "```python\n",
        "pip install qiskit-aer-gpu\n",
        "```\n",
        "\n",
        "The package above is for CUDA&reg 12, so if your system has CUDA® 11 installed, install separate package:\n",
        "\n",
        "```python\n",
        "pip install qiskit-aer-gpu-cu11\n",
        "```\n",
        "\n",
        "This will overwrite your current `qiskit-aer` package installation giving you the same functionality found in the canonical `qiskit-aer` package, plus the ability to run the GPU supported simulators: `statevector`, `density matrix`, and `unitary`.\n",
        "\n",
        "Note: This package is only available on x86_64 Linux. For other platforms that have CUDA support, you will have to build from source. You can refer to the [contributing guide](https://github.com/Qiskit/qiskit-aer/blob/main/CONTRIBUTING.md#building-with-gpu-support) for instructions on doing this."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "metadata": {
        "id": "yQcWcPcjTZL7"
      },
      "outputs": [],
      "source": [
        "from qiskit_aer import AerError\n",
        "\n",
        "# Initialize a GPU backend\n",
        "# Note that the cloud instance for tutorials does not have a GPU\n",
        "# so this will raise an exception.\n",
        "try:\n",
        "    simulator_gpu = AerSimulator(method='tensor_network', device='GPU')\n",
        "\n",
        "except AerError as e:\n",
        "    print(e)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eKTD_kxGVL_q"
      },
      "source": [
        "### Simulation Precision\n",
        "\n",
        "One of the available simulator options allows setting the float precision for the `statevector`, `density_matrix`, `unitary` and `superop` methods. This is done using the `set_precision=\"single\"` or `precision=\"double\"` (default) option:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "9W07XP4ZTpqJ",
        "outputId": "e585ddd8-e594-4e1f-8e1b-7a463b458b8c"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{'00': 505, '11': 519}\n"
          ]
        }
      ],
      "source": [
        "simulator = AerSimulator(method='statevector')\n",
        "simulator.set_options(precision='single')\n",
        "\n",
        "# Run and get counts\n",
        "result = simulator.run(circ).result()\n",
        "counts = result.get_counts(circ)\n",
        "print(counts)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QtlisMIMVg3J"
      },
      "source": [
        "Setting the simulation precision applies to both CPU and GPU simulation devices. Single precision will halve the required memory and may provide performance improvements on certain systems."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Custom Simulator Instructions"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Saving the simulator state\n",
        "\n",
        "The state of the simulator can be saved in a variety of formats using custom simulator instructions.\n",
        "\n",
        "\n",
        "| Circuit method | Description |Supported Methods | \n",
        "|----------------|-------------|------------------|\n",
        "| `save_state` | Save the simulator state in the native format for the simulation method | All | \n",
        "| `save_statevector` | Save the simulator state as a statevector | `\"automatic\"`, `\"statevector\"`, `\"matrix_product_state\"`, `\"extended_stabilizer\"`|\n",
        "| `save_stabilizer` | Save the simulator state as a Clifford stabilizer | `\"automatic\"`, `\"stabilizer\"`| \n",
        "| `save_density_matrix` | Save the simulator state as a density matrix | `\"automatic\"`, `\"statevector\"`, `\"matrix_product_state\"`, `\"density_matrix\"` |\n",
        "| `save_matrix_product_state` | Save the simulator state as a a matrix product state tensor | `\"automatic\"`, `\"matrix_product_state\"`|\n",
        "| `save_unitary` | Save the simulator state as unitary matrix of the run circuit | `\"automatic\"`, `\"unitary\"`|\n",
        "| `save_superop` | Save the simulator state as superoperator matrix of the run circuit | `\"automatic\"`, `\"superop\"`|\n",
        "\n",
        "Note that these instructions are only supported by the Aer simulator and will result in an error if a circuit containing them is run on a non-simulator backend such as an IBM Quantum device."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yvwkMWpdVjqg"
      },
      "source": [
        "### Saving the final statevector\n",
        "To save the final statevector of the simulation we can append the circuit with the `save_statevector` instruction. Note that this instruction should be applied before any measurements if we do not want to save the collapsed post-measurement state\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 820
        },
        "id": "QIZ90hUAVeW5",
        "outputId": "44cc3f7c-2532-4ff3-e04e-e774c0fefe8f"
      },
      "outputs": [
        {
          "data": {
            "image/png": "[encoded data, 205504 characters]",
            "text/plain": [
              "<Figure size 1600x800 with 2 Axes>"
            ]
          },
          "execution_count": 16,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Construct quantum circuit without measure\n",
        "circ = QuantumCircuit(2)\n",
        "circ.h(0)\n",
        "circ.cx(0, 1)\n",
        "circ.save_statevector()\n",
        "\n",
        "# Transpile for simulator\n",
        "simulator = AerSimulator(method='statevector')\n",
        "circ = transpile(circ, simulator)\n",
        "\n",
        "# Run and get statevector\n",
        "result = simulator.run(circ).result()\n",
        "statevector = result.get_statevector(circ)\n",
        "plot_state_city(statevector, title='Bell state')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "T9iR2p-PV0Qx"
      },
      "source": [
        "\n",
        "### Saving the circuit unitary\n",
        "\n",
        "To save the unitary matrix for a `QuantumCircuit` we can append the circuit with the `save_unitary` instruction. Note that this circuit cannot contain any measurements or resets since these instructions are not supported on for the `\"unitary\"` simulation method\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "kNzLjdLFVwM4",
        "outputId": "7c5c8ad5-1a99-450c-d360-70250c12f236"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Circuit unitary:\n",
            " [[ 0.70711+0.j  0.70711-0.j  0.     +0.j  0.     +0.j]\n",
            " [ 0.     +0.j  0.     +0.j  0.70711+0.j -0.70711+0.j]\n",
            " [ 0.     +0.j  0.     +0.j  0.70711+0.j  0.70711-0.j]\n",
            " [ 0.70711+0.j -0.70711+0.j  0.     +0.j  0.     +0.j]]\n"
          ]
        }
      ],
      "source": [
        "# Construct quantum circuit without measure\n",
        "circ = QuantumCircuit(2)\n",
        "circ.h(0)\n",
        "circ.cx(0, 1)\n",
        "circ.save_unitary()\n",
        "\n",
        "# Transpile for simulator\n",
        "simulator = AerSimulator(method = 'unitary')\n",
        "circ = transpile(circ, simulator)\n",
        "\n",
        "# Run and get unitary\n",
        "result = simulator.run(circ).result()\n",
        "unitary = result.get_unitary(circ)\n",
        "print(\"Circuit unitary:\\n\", np.asarray(unitary).round(5))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0ap3rpflWDRY"
      },
      "source": [
        "\n",
        "### Saving multiple states\n",
        "\n",
        "We can also apply save instructions at multiple locations in a circuit. Note that when doing this we must provide a unique label for each instruction to retrieve them from the results\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "KSYho6W8WBkI",
        "outputId": "7871b3c9-6f33-4677-e9fb-70afe7bd0f00"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'psi_5': Statevector([-1.+0.00000000e+00j,  0.-5.55111512e-17j],\n",
              "             dims=(2,)),\n",
              " 'psi_4': Statevector([-0.30901699+0.j        ,  0.        -0.95105652j],\n",
              "             dims=(2,)),\n",
              " 'psi_3': Statevector([0.58778525+0.j        , 0.        -0.80901699j],\n",
              "             dims=(2,)),\n",
              " 'psi_2': Statevector([0.95105652+0.j        , 0.        -0.30901699j],\n",
              "             dims=(2,)),\n",
              " 'psi_1': Statevector([1.+0.j, 0.+0.j],\n",
              "             dims=(2,)),\n",
              " 'psi_0': Statevector([1.+0.j, 0.+0.j],\n",
              "             dims=(2,))}"
            ]
          },
          "execution_count": 18,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Construct quantum circuit without measure\n",
        "steps = 5\n",
        "circ = QuantumCircuit(1)\n",
        "for i in range(steps):\n",
        "    circ.save_statevector(label=f'psi_{i}')\n",
        "    circ.rx(i * np.pi / steps, 0)\n",
        "circ.save_statevector(label=f'psi_{steps}')\n",
        "\n",
        "# Transpile for simulator\n",
        "simulator = AerSimulator(method= 'automatic')\n",
        "circ = transpile(circ, simulator)\n",
        "\n",
        "# Run and get saved data\n",
        "result = simulator.run(circ).result()\n",
        "data = result.data(0)\n",
        "data"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lCM2Zy0SWLq8"
      },
      "source": [
        "### Setting the simulator to a custom state\n",
        "\n",
        "The `AerSimulator` allows setting a custom simulator state for several of its simulation methods using custom simulator instructions\n",
        "\n",
        "| Circuit method | Description |Supported Methods | \n",
        "|----------------|-------------|------------------|\n",
        "| `set_statevector` | Set the simulator state to the specified statevector | `\"automatic\"`, `\"statevector\"`, `\"density_matrix\"`|\n",
        "| `set_stabilizer` | Set the simulator state to the specified Clifford stabilizer | `\"automatic\"`, `\"stabilizer\"`| \n",
        "| `set_density_matrix` | Set the simulator state to the specified  density matrix | `\"automatic\"`, `\"density_matrix\"` |\n",
        "| `set_unitary` | Set the simulator state to the specified  unitary matrix | `\"automatic\"`, `\"unitary\"`, `\"superop\"`|\n",
        "| `set_superop` | Set the simulator state to the specified superoperator matrix | `\"automatic\"`, `\"superop\"`|\n",
        "\n",
        "\n",
        "**Notes:**\n",
        "* These instructions must be applied to all qubits in a circuit, otherwise an exception will be raised.\n",
        "* The input state must also be a valid state (statevector, density matrix, unitary etc) otherwise an exception will be raised.\n",
        "* These instructions can be applied at any location in a circuit and will override the current state with the specified one. Any classical register values (e.g. from preceding measurements) will be unaffected\n",
        "* Set state instructions are only supported by the Aer simulator and will result in an error if a circuit containing them is run on a non-simulator backend such as an IBM Quantum device."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LQ-0aFF8WQjV"
      },
      "source": [
        "#### Setting a Custom Statevector\n",
        "\n",
        "The set_statevector instruction can be used to set a custom Statevector state. The input statevector must be valid ($|\\langle\\psi|\\psi\\rangle|=1$)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "tPRaGfd2WJMZ",
        "outputId": "ca03e66c-0dd0-473d-d433-b2e554aa9722"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'statevector': Statevector([-0.49859823-0.41410205j,  0.12480824+0.46132192j,\n",
              "               0.33634191+0.30214216j,  0.234309  +0.3036574j ],\n",
              "             dims=(2, 2))}"
            ]
          },
          "execution_count": 19,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Generate a random statevector\n",
        "num_qubits = 2\n",
        "psi = qi.random_statevector(2 ** num_qubits, seed=100)\n",
        "\n",
        "# Set initial state to generated statevector\n",
        "circ = QuantumCircuit(num_qubits)\n",
        "circ.set_statevector(psi)\n",
        "circ.save_state()\n",
        "\n",
        "# Transpile for simulator\n",
        "simulator = AerSimulator(method='statevector')\n",
        "circ = transpile(circ, simulator)\n",
        "\n",
        "# Run and get saved data\n",
        "result = simulator.run(circ).result()\n",
        "result.data(0)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZLB4ehiEWfU9"
      },
      "source": [
        "#### Using the initialize instruction\n",
        "\n",
        "It is also possible to initialize the simulator to a custom statevector using the `initialize` instruction. Unlike the `set_statevector` instruction this instruction is also supported on real device backends by unrolling to reset and standard gate instructions."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "FDDJgfYEWcK6",
        "outputId": "527c50db-d0e1-4615-9ee4-e4bd9eda9df8"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'statevector': Statevector([-0.49859823-0.41410205j,  0.12480824+0.46132192j,\n",
              "               0.33634191+0.30214216j,  0.234309  +0.3036574j ],\n",
              "             dims=(2, 2))}"
            ]
          },
          "execution_count": 20,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Use initilize instruction to set initial state\n",
        "circ = QuantumCircuit(num_qubits)\n",
        "circ.initialize(psi, range(num_qubits))\n",
        "circ.save_state()\n",
        "\n",
        "# Transpile for simulator\n",
        "simulator = AerSimulator(method= 'statevector')\n",
        "circ = transpile(circ, simulator)\n",
        "\n",
        "# Run and get result data\n",
        "result = simulator.run(circ).result()\n",
        "result.data(0)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZFXx_joWWmct"
      },
      "source": [
        "#### Setting a custom density matrix\n",
        "\n",
        "The `set_density_matrix` instruction can be used to set a custom `DensityMatrix` state. The input density matrix must be valid ($Tr[\\rho]=1, \\rho \\ge 0$)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "plZWFBv2WkoZ",
        "outputId": "1a557650-d87d-46eb-a00e-2342817aa156"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'density_matrix': DensityMatrix([[ 0.2075308 +0.j        ,  0.13161422-0.01760848j,\n",
              "                  0.0442826 +0.07742704j,  0.04852053-0.01303171j],\n",
              "                [ 0.13161422+0.01760848j,  0.20106116+0.j        ,\n",
              "                  0.02568549-0.03689812j,  0.0482903 -0.04367912j],\n",
              "                [ 0.0442826 -0.07742704j,  0.02568549+0.03689812j,\n",
              "                  0.39731492+0.j        , -0.01114025-0.13426423j],\n",
              "                [ 0.04852053+0.01303171j,  0.0482903 +0.04367912j,\n",
              "                 -0.01114025+0.13426423j,  0.19409312+0.j        ]],\n",
              "               dims=(2, 2))}"
            ]
          },
          "execution_count": 21,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "num_qubits = 2\n",
        "rho = qi.random_density_matrix(2 ** num_qubits, seed=100)\n",
        "circ = QuantumCircuit(num_qubits)\n",
        "circ.set_density_matrix(rho)\n",
        "circ.save_state()\n",
        "\n",
        "# Transpile for simulator\n",
        "simulator = AerSimulator(method='density_matrix')\n",
        "circ = transpile(circ, simulator)\n",
        "\n",
        "# Run and get saved data\n",
        "result = simulator.run(circ).result()\n",
        "result.data(0)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JTr8TswdWuCZ"
      },
      "source": [
        "#### Setting a custom stabilizer state\n",
        "\n",
        "The `set_stabilizer` instruction can be used to set a custom `Clifford` stabilizer state. The input stabilizer must be a valid `Clifford`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "qVwlRcf6WsAb",
        "outputId": "c732a2e0-5cfd-4623-f9d9-648542df8380"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'stabilizer': StabilizerState(['+ZZ', '-IZ'])}"
            ]
          },
          "execution_count": 22,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Generate a random Clifford C\n",
        "num_qubits = 2\n",
        "stab = qi.random_clifford(num_qubits, seed=100)\n",
        "\n",
        "# Set initial state to stabilizer state C|0>\n",
        "circ = QuantumCircuit(num_qubits)\n",
        "circ.set_stabilizer(stab)\n",
        "circ.save_state()\n",
        "\n",
        "# Transpile for simulator\n",
        "simulator = AerSimulator(method= \"stabilizer\")\n",
        "circ = transpile(circ, simulator)\n",
        "\n",
        "# Run and get saved data\n",
        "result = simulator.run(circ).result()\n",
        "result.data(0)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ex70kNx6W2Z7"
      },
      "source": [
        "#### Setting a custom unitary\n",
        "\n",
        "The `set_unitary` instruction can be used to set a custom unitary `Operator` state. The input unitary matrix must be valid ($U^\\dagger U=\\mathbb{1}$)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "lJuGWd9pW0HZ",
        "outputId": "bf26add3-bbdd-47bd-e60c-32a5472beb89"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'unitary': Operator([[-0.44885724-0.26721573j,  0.10468034-0.00288681j,\n",
              "             0.4631425 +0.15474915j, -0.11151309-0.68210936j],\n",
              "           [-0.37279054-0.38484834j,  0.3820592 -0.49653433j,\n",
              "             0.14132327-0.17428515j,  0.19643043+0.48111423j],\n",
              "           [ 0.2889092 +0.58750499j,  0.39509694-0.22036424j,\n",
              "             0.49498355+0.2388685j ,  0.25404989-0.00995706j],\n",
              "           [ 0.01830684+0.10524311j,  0.62584001+0.01343146j,\n",
              "            -0.52174025-0.37003296j,  0.12232823-0.41548904j]],\n",
              "          input_dims=(2, 2), output_dims=(2, 2))}"
            ]
          },
          "execution_count": 23,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Generate a random unitary\n",
        "num_qubits = 2\n",
        "unitary = qi.random_unitary(2 ** num_qubits, seed=100)\n",
        "\n",
        "# Set initial state to unitary\n",
        "circ = QuantumCircuit(num_qubits)\n",
        "circ.set_unitary(unitary)\n",
        "circ.save_state()\n",
        "\n",
        "# Transpile for simulator\n",
        "simulator = AerSimulator(method='unitary')\n",
        "circ = transpile(circ, simulator)\n",
        "\n",
        "# Run and get saved data\n",
        "result = simulator.run(circ).result()\n",
        "result.data(0)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 37,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 35
        },
        "id": "CImqrva-W9SQ",
        "outputId": "b23060be-8135-40ca-e70e-a82f2251512b"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            },
            "text/plain": [
              "'1.0.1'"
            ]
          },
          "execution_count": 37,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit\n",
        "qiskit.__version__"
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "gpuType": "T4",
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
