{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# Executing Quantum Circuits \n", "\n", "In CUDA Quantum, quantum circuits are stored as quantum kernels. For estimating the probability distribution of a measured quantum state in a circuit, we use the `sample` function call, and for computing the expectation value of a quantum state with a given observable, we use the `observe` function call. \n", "\n", "## Sample\n", "\n", "Quantum states collapse upon measurement and hence need to be sampled many times to gather statistics. The CUDA Quantum `sample` call enables this: \n", "\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " ╭───╮ \n", "q0 : ┤ h ├──●──\n", " ╰───╯╭─┴─╮\n", "q1 : ─────┤ x ├\n", " ╰───╯\n", "\n", "{ 00:483 11:517 }\n", "\n" ] } ], "source": [ "import cudaq\n", "\n", "qubit_count = 2\n", "\n", "# Define the simulation target.\n", "cudaq.set_target(\"qpp-cpu\")\n", "\n", "# Define a quantum kernel function.\n", "\n", "\n", "@cudaq.kernel\n", "def kernel(qubit_count: int):\n", " qvector = cudaq.qvector(qubit_count)\n", "\n", " # 2-qubit GHZ state.\n", " h(qvector[0])\n", " for i in range(1, qubit_count):\n", " x.ctrl(qvector[0], qvector[i])\n", "\n", " # If we dont specify measurements, all qubits are measured in\n", " # the Z-basis by default.\n", " mz(qvector)\n", "\n", "\n", "print(cudaq.draw(kernel, qubit_count))\n", "\n", "result = cudaq.sample(kernel, qubit_count, shots_count=1000)\n", "\n", "print(result)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Note that there is a subtle difference between how `sample` is executed with the target device set to a simulator or with the target device set to a QPU. In simulation mode, the quantum state is built once and then sampled $s$ times where $s$ equals the `shots_count`. In hardware execution mode, the quantum state collapses upon measurement and hence needs to be rebuilt over and over again. \n", "\n", "\n" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### Sample Async\n", "\n", "Asynchronous programming is a technique that enables your program to start a potentially long-running task and still be able to be responsive to other events while that task runs, rather than having to wait until that task has finished. Once that task has finished, your program is presented with the result. \n", "\n", "`sample` can be a time intensive task. We can parallelize the execution of `sample` via the arguments it accepts. " ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{ 00:480 11:520 }\n", "\n", "{ 00:487 11:513 }\n", "\n" ] } ], "source": [ "# Parallelize over the various kernels one would like to execute.\n", "\n", "import cudaq\n", "\n", "qubit_count = 2\n", "\n", "# Set the simulation target.\n", "cudaq.set_target(\"nvidia-mqpu\")\n", "\n", "# Kernel 1\n", "\n", "\n", "@cudaq.kernel\n", "def kernel_1(qubit_count: int):\n", " qvector = cudaq.qvector(qubit_count)\n", "\n", " # 2-qubit GHZ state.\n", " h(qvector[0])\n", " for i in range(1, qubit_count):\n", " x.ctrl(qvector[0], qvector[i])\n", "\n", " # If we dont specify measurements, all qubits are measured in\n", " # the Z-basis by default.\n", " mz(qvector)\n", "\n", "\n", "# Kernel 2\n", "\n", "\n", "@cudaq.kernel\n", "def kernel_2(qubit_count: int):\n", " qvector = cudaq.qvector(qubit_count)\n", "\n", " # 2-qubit GHZ state.\n", " h(qvector[0])\n", " for i in range(1, qubit_count):\n", " x.ctrl(qvector[0], qvector[i])\n", "\n", " # If we dont specify measurements, all qubits are measured in\n", " # the Z-basis by default.\n", " mz(qvector)\n", "\n", "\n", "# Asynchronous execution on multiple qpus via nvidia gpus.\n", "result_1 = cudaq.sample_async(kernel_1, qubit_count, shots_count=1000, qpu_id=0)\n", "result_2 = cudaq.sample_async(kernel_2, qubit_count, shots_count=1000, qpu_id=1)\n", "\n", "print(result_1.get())\n", "print(result_2.get())" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Similar to the above, one can also parallelize over the `shots_count` or the variational parameters of a quantum circuit." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## Observe\n", "\n", "The `observe` function allows us to gather qubit statistics and calculate expectation values. We must supply a spin operator in the form of a Hamiltonian from which we would like to calculate $\\bra{\\psi}H\\ket{\\psi}$." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " = -1.0000000000000002\n" ] } ], "source": [ "import cudaq\n", "from cudaq import spin\n", "\n", "qubit_count = 2\n", "\n", "# Define the simulation target.\n", "cudaq.set_target(\"qpp-cpu\")\n", "\n", "# Using the same quantum kernel function as we did with `sample`.\n", "\n", "# Define a Hamiltonian in terms of Pauli Spin operators.\n", "hamiltonian = spin.z(0) + spin.y(1) + spin.x(0) * spin.z(0)\n", "\n", "# Compute the expectation value given the state prepared by the kernel.\n", "result = cudaq.observe(kernel, hamiltonian, qubit_count).expectation()\n", "\n", "print(' =', result)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Observe Async\n", "\n", "Similar to `sample_async` above, `observe` also supports asynchronous execution for the [arguments it accepts](https://nvidia.github.io/cuda-quantum/latest/api/languages/python_api.html#cudaq.sample_async:~:text=cudaq.observe_async(),%C2%B6). One can parallelize over various kernels, spin operators, variational parameters or even noise models." ] } ], "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.10.12" }, "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" } } }, "nbformat": 4, "nbformat_minor": 2 }