{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Resource Estimation of Random Circuit Used in State Vector Simulation\n",
        "\n",
        "This notebook gives the resource estimation of random quantum circuits used for the full state vector simulation in\n",
        "[Simulating 44-Qubit quantum circuits using AWS ParallelCluster](https://aws.amazon.com/blogs/hpc/simulating-44-qubit-quantum-circuits-using-aws-parallelcluster/)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import qsharp"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Generating a random circuit\n",
        "\n",
        "Let's now create a random Q# program. Note that the generated circuit will be different on each run, so resource estimates produced for it will vary slightly."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "microsoft": {
          "language": "qsharp"
        },
        "vscode": {
          "languageId": "qsharp"
        }
      },
      "outputs": [],
      "source": [
        "%%qsharp\n",
        "open Microsoft.Quantum.Math;\n",
        "open Microsoft.Quantum.Random;\n",
        "\n",
        "operation RunRandomCircuit(nQubits : Int, nGates : Int) : Unit {\n",
        "    use qs = Qubit[nQubits];\n",
        "\n",
        "    for _ in 1 .. nGates {\n",
        "        let rnd = DrawRandomDouble(0., 1.);\n",
        "        if rnd < 0.5 {\n",
        "            // CZ\n",
        "            let controlInd = DrawRandomInt(0, nQubits - 1);\n",
        "            // Make sure target qubit index is distinct from control qubit index\n",
        "            mutable targetInd = DrawRandomInt(0, nQubits - 2);\n",
        "            if targetInd >= controlInd {\n",
        "                set targetInd += 1;\n",
        "            }\n",
        "            CZ(qs[controlInd], qs[targetInd]);\n",
        "        } elif rnd < 0.625 {\n",
        "            // H\n",
        "            let ind = DrawRandomInt(0, nQubits - 1);\n",
        "            H(qs[ind]);\n",
        "        } else {\n",
        "            // R\n",
        "            let ind = DrawRandomInt(0, nQubits - 1);\n",
        "            let gate = [Rx, Ry, Rz][DrawRandomInt(0, 2)];\n",
        "            let angle = DrawRandomDouble(0., PI());\n",
        "            gate(angle, qs[ind]);\n",
        "        }\n",
        "    }\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Running the Resource Estimator\n",
        "\n",
        "Now we can estimate the resources required for the generated Q# program."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "n_qubits = 43\n",
        "n_gates = 1000\n",
        "qsharp.set_classical_seed(12)\n",
        "result = qsharp.estimate(f\"RunRandomCircuit({n_qubits}, {n_gates})\")\n",
        "result"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "jupyter": {
          "outputs_hidden": false,
          "source_hidden": false
        },
        "nteract": {
          "transient": {
            "deleting": false
          }
        }
      },
      "outputs": [],
      "source": [
        "logical_qubits = result['physicalCounts']['breakdown']['algorithmicLogicalQubits']\n",
        "logical_depth = result['physicalCounts']['breakdown']['algorithmicLogicalDepth']\n",
        "# We take the runtime of the circuit from the blog post https://aws.amazon.com/blogs/hpc/simulating-44-qubit-quantum-circuits-using-aws-parallelcluster/, figure 4.\n",
        "target_runtime = 5800\n",
        "target_rqops = logical_qubits * logical_depth / target_runtime\n",
        "\n",
        "print(f\"Logical qubits = {logical_qubits}\")\n",
        "print(f\"Logical depth = {logical_depth}\")\n",
        "print(f\"Target runtime = {target_runtime} seconds\")\n",
        "print(f\"Target rQOPS = {target_rqops}\")\n",
        "\n",
        "print(f\"Execution time on hardware  = {result['physicalCounts']['runtime'] * 1e-9} seconds\")\n",
        "print(f\"rQOPS for execution on hardware = {result['physicalCounts']['rqops']}\")"
      ]
    }
  ],
  "metadata": {
    "kernel_info": {
      "name": "python3"
    },
    "kernelspec": {
      "display_name": "Python 3 (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.11.7"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 1
}
