{ "cells": [ { "cell_type": "markdown", "id": "811812db", "metadata": {}, "source": [ "(sec-tutorial-experiment)=\n", "\n", "# Tutorial: Running an Experiment\n", "\n", "```{seealso}\n", "The complete source code of this tutorial can be found in\n", "\n", "{nb-download}`Running an Experiment.ipynb`\n", "\n", "The example dataset can be downloaded {download}`here <../examples/dataset.hdf5>`.\n", "```\n", "\n", "This notebook presents a structure for setting up experiments using a\n", "combination of `quantify-scheduler` and `quantify-core`. `quantify-scheduler`\n", "provides a high-level interface with the hardware, allowing users to abstract\n", "hardware-specific nuances. `quantify-core`, on the other hand, serves as an\n", "experiment management tool, using `quantify-scheduler` as its hardware\n", "interface. This allows users to manage, execute, and analyze experiments easily.\n", "\n", "The following is a general workflow for using Quantify\n", "\n", "- **{ref}`initial_setup`**\n", " - Set the directory for data storage for the experiment\n", " - Initialize the {class}`~quantify_core.measurement.control.MeasurementControl` and {class}`~quantify_scheduler.instrument_coordinator.instrument_coordinator.InstrumentCoordinator` objects\n", "\n", "- **{ref}`device_setup`**\n", " - Set up a *device compilation configuration* for the *device under test*\n", "\n", "- **{ref}`hardware_setup`**\n", " - Connect to the *control hardware*\n", " - Set up the *hardware compilation configuration*\n", "\n", "- **{ref}`create_schedule`**\n", " - Create a *schedule* containing the timeline of operations for the experiment\n", " - *Compile* the schedule to control-hardware code\n", " - *Visualize* the schedule\n", "\n", "- **{ref}`run_experiment`**\n", " - Setup {class}`~quantify_core.measurement.control.MeasurementControl` to run the experiment\n", " - *Run* the experiment\n", " - *Analyze* the results\n", "\n", "\n", "(initial_setup)=\n", "## 1. Initial Setup\n", "We first set up the directory in which all experimental data will be stored and managed." ] }, { "cell_type": "code", "execution_count": 1, "id": "988ab6eb", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Data will be saved in:\n", "/root/quantify-data\n" ] } ], "source": [ "from quantify_core.data import handling as dh\n", "dh.set_datadir()" ] }, { "cell_type": "markdown", "id": "10f25e71", "metadata": {}, "source": [ "Next, we need to initialize two classes:\n", "{class}`~quantify_core.measurement.control.MeasurementControl` for managing the\n", "experiment and {class}`~quantify_scheduler.instrument_coordinator.instrument_coordinator.InstrumentCoordinator` for managing the control hardware." ] }, { "cell_type": "code", "execution_count": 2, "id": "2000b86b", "metadata": {}, "outputs": [], "source": [ "from quantify_core.measurement.control import MeasurementControl\n", "from quantify_scheduler.instrument_coordinator import InstrumentCoordinator\n", "\n", "measurement_control = MeasurementControl(\"measurement_control\")\n", "instrument_coordinator = InstrumentCoordinator(\"instrument_coordinator\")" ] }, { "cell_type": "markdown", "id": "2188be6f", "metadata": {}, "source": [ "(device_setup)=\n", "## 2. Device Setup\n", "\n", "We set up the quantum device on which we perform the actual experiments.\n", "This one-qubit chip is represented by {class}`~quantify_scheduler.device_under_test.quantum_device.QuantumDevice` where we add a single\n", "transmon qubit (represented by {class}`~quantify_scheduler.device_under_test.transmon_element.BasicTransmonElement`) `q0` to it." ] }, { "cell_type": "code", "execution_count": 3, "id": "7aa0aefa", "metadata": {}, "outputs": [], "source": [ "# Device parameters\n", "ACQ_DELAY = 100e-9\n", "FREQ_01 = 4e9\n", "READOUT_AMP = 0.1\n", "READOUT_FREQ = 4.3e9\n", "PI_PULSE_AMP = 0.15\n", "LO_FREQ_QUBIT = 3.9e9\n", "LO_FREQ_READOUT = 4.5e9" ] }, { "cell_type": "code", "execution_count": 4, "id": "d0c8623a", "metadata": {}, "outputs": [], "source": [ "from quantify_scheduler.device_under_test.quantum_device import QuantumDevice\n", "from quantify_scheduler.device_under_test.transmon_element import BasicTransmonElement\n", "\n", "single_qubit_device = QuantumDevice(\"single_qubit_device\")\n", "single_qubit_device.instr_instrument_coordinator(instrument_coordinator.name)\n", "\n", "q0 = BasicTransmonElement(\"q0\")\n", "single_qubit_device.add_element(q0)\n", "\n", "# Assign device parameters to transmon element\n", "q0.measure.pulse_amp(READOUT_AMP)\n", "q0.clock_freqs.readout(READOUT_FREQ)\n", "q0.clock_freqs.f01(FREQ_01)\n", "q0.measure.acq_delay(ACQ_DELAY)\n", "q0.rxy.amp180(PI_PULSE_AMP)" ] }, { "cell_type": "markdown", "id": "4b61c91c", "metadata": {}, "source": [ "```{admonition} Quantum Devices and Elements\n", "More information on quantum devices and elements can be found in\n", "{ref}`sec-tutorial-ops-qubits`.\n", "```\n", "\n", "(hardware_setup)=\n", "## 3. Hardware Setup\n", "\n", "Let us now set up the connections to the control hardware. In this example, we\n", "use a dummy Qblox device that is created via an instance of the\n", "{class}`~qblox_instruments.Cluster` class, and is initialized with a dummy\n", "configuration consisting of a readout module in slot `1` and a control module in\n", "slot `2`." ] }, { "cell_type": "code", "execution_count": 5, "id": "04b06950", "metadata": {}, "outputs": [], "source": [ "from qblox_instruments import Cluster, ClusterType\n", "from quantify_scheduler.instrument_coordinator.components.qblox import ClusterComponent\n", "cluster = Cluster(\n", " \"cluster\",\n", " dummy_cfg={\n", " 1: ClusterType.CLUSTER_QRM,\n", " 2: ClusterType.CLUSTER_QCM_RF,\n", " },\n", ")\n", "\n", "ic_cluster = ClusterComponent(cluster)\n", "instrument_coordinator.add_component(ic_cluster)" ] }, { "cell_type": "markdown", "id": "0cdd83f7", "metadata": {}, "source": [ "The last part of setting up the hardware is to define the {class}`~.backends.types.common.HardwareCompilationConfig`\n", "and attach it to our `single_qubit_device`. The hardware compilation configuration is a\n", "pydantic datastructure, parsed either from a file or from a Python\n", "dictionary. It contains all of the information about the instruments used to run\n", "the experiment and is used to compile the schedule to hardware.\n", "For more information on this datastructure, please refer to the explanation in the {ref}`User Guide `." ] }, { "cell_type": "code", "execution_count": 6, "id": "723d471a", "metadata": {}, "outputs": [], "source": [ "hardware_comp_cfg = {\n", " \"config_type\": \"quantify_scheduler.backends.qblox_backend.QbloxHardwareCompilationConfig\",\n", " \"hardware_description\": {\n", " f\"{cluster.name}\": {\n", " \"instrument_type\": \"Cluster\",\n", " \"ref\": \"internal\",\n", " \"modules\": {\n", " \"1\": {\n", " \"instrument_type\": \"QRM_RF\"\n", " },\n", " \"2\": {\n", " \"instrument_type\": \"QCM_RF\"\n", " },\n", " },\n", " },\n", " },\n", " \"hardware_options\": {\n", " \"modulation_frequencies\": {\n", " \"q0:res-q0.ro\": {\"lo_freq\": LO_FREQ_READOUT},\n", " \"q0:mw-q0.01\": {\"lo_freq\": LO_FREQ_QUBIT},\n", " },\n", " },\n", " \"connectivity\": {\n", " \"graph\": [\n", " (f\"{cluster.name}.{cluster.module1.name.split('_')[-1]}.complex_output_0\", \"q0:res\"),\n", " (f\"{cluster.name}.{cluster.module2.name.split('_')[-1]}.complex_output_0\", \"q0:mw\")\n", " ]\n", " },\n", "}" ] }, { "cell_type": "code", "execution_count": 7, "id": "f9e417fe", "metadata": {}, "outputs": [], "source": [ "# Tie hardware config to device\n", "single_qubit_device.hardware_config(hardware_comp_cfg)" ] }, { "cell_type": "markdown", "id": "23894a49", "metadata": {}, "source": [ "(create_schedule)=\n", "## 4. Schedule Definition and Compilation\n", "Now we must create a schedule, where we define the set of operations that we\n", "wish to perform on the device under test. We define the schedule independent of\n", "the hardware configuration and rely on Quantify's ability to compile a schedule\n", "to hardware for converting it to hardware-level commands. For this tutorial, we\n", "will define a simple schedule that will run a *T1 experiment* to determine the\n", "relaxation time of our qubit. For various delay times `tau`, we repeatedly\n", "excite the qubit, wait `tau` seconds and then measure the qubit." ] }, { "cell_type": "code", "execution_count": 8, "id": "08f07bb3", "metadata": {}, "outputs": [], "source": [ "from quantify_scheduler import Schedule\n", "from quantify_scheduler.operations.gate_library import Measure, Reset, X\n", "\n", "def t1_sched(times, repetitions=1):\n", " schedule = Schedule(\"T1\", repetitions)\n", " for i, tau in enumerate(times):\n", " schedule.add(Reset(\"q0\"), label=f\"Reset {i}\")\n", " schedule.add(X(\"q0\"), label=f\"pi {i}\")\n", " schedule.add(\n", " Measure(\"q0\", acq_index=i),\n", " ref_pt=\"start\",\n", " rel_time=tau,\n", " label=f\"Measurement {i}\",\n", " )\n", " return schedule" ] }, { "cell_type": "markdown", "id": "354b7845", "metadata": {}, "source": [ "```{admonition} Pre-defined Schedules\n", ":class: tip\n", "\n", "The T1 schedule can be imported with `from quantify_scheduler.schedules import t1_sched`.\n", "\n", "For more pre-defined schedules, see {mod}`quantify_scheduler.schedules`.\n", "```\n", "\n", "We can inspect the details of the schedule in three different ways: via (1)\n", "*circuit* and (2) *pulse diagrams*, or through (3) a *timing table* containing the\n", "timing and other information of each operation.\n", "\n", "The\n", "{meth}`~quantify_scheduler.schedules.schedule.ScheduleBase.plot_circuit_diagram`\n", "method can directly be used to display the quantum circuit that corresponds to\n", "the schedule that we defined above." ] }, { "cell_type": "code", "execution_count": 9, "id": "f1a51825", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAWMAAAB3CAYAAADW8iHYAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAMx0lEQVR4nO3df3BVZX7H8fdzbxJIImxQhsC6YlyXaMOvUCgstkK6RMGkEiJSWQbFDMOMWNih6UQpRSo/Sh1cBWSRBF2om51FBsHkAh1UAtql2jAbFSqUH8WsYVOJ0q2kSSOE3Kd/JGQTICE/7uU8ST6vmTuZ+5xzz/nm5OZzn/uc59xrrLWIiIi3fF4XICIiCmMREScojEVEHKAwFhFxgMJYRMQBCmMREQcojEVEHKAwFhFxgMJYRMQBCmMREQcojKXbMcbYNt5SGtafb4zZYYwpa2j/J09/AemRIrwuQCQMHr/q/hPAA9dp/4+Gn88CfYDDwKDwliZyfQpj6Xastb9set8Y80Pggavbm5gIlFlrrTGmKuwFilyHwlh6PGvtF17XIKIxYxERByiMRUQcoDAWEXGAwlhExAEKYxERByiMRUQcoDAWEXGA5hlLj2eMeRgY2XA3EhhhjFnacD9grT3qTWXSkyiMRWA6MKfJ/VENN4DfAQpjCTtjrfW6BhGRHk9jxiIiDlAYi4g4QGEsIuIAhbGIiAMUxiIiDlAYi4g4QGEsIuIAVy/60ORnEekuTFtWUs9YRMQBCmMREQcojEVEHKAwFhFxgMJYRMQBCmMREQcojEVEHKAwFhFxgMJYRMQBCmMREQcojEVEHKAwFhFxgMJYRMQBCmMREQcojEVEHKAwFhFxgMJYRMQBCmMREQe4+rVL0oNsOPBbr0u46Rb+KKFTjz9x4kRoCulC7r33Xq9LCCv1jEVEHKAwFhFxgMJYRMQBCmMREQcojEUkpE6cOEFdXZ3XZXQ5CmMRCZn9+/eTmZnJmjVrvC6ly1EYi0hInDlzhpycHAB8PkVLe+mIiUinVVVVMX/+fGpra/H7/URFRXldUpejMBaRTgkGgzzzzDOUl5dTV1eHMUZh3AG6Ak9EOiUvL4+DBw823rfWKow7QD1jEemwDz74gA0bNjRrs9YSGRnpUUVdl8JYRDqkvLyc7Ozsa9rVM+4YhXEX8v7775OQkNCux2zZsqVHfqjMFcFgkFVPTmLPz19s1n7s3w7w15MTOfLrfR5V1vVdvnyZmpoajDHN2hXGHaMw7uI2btxIQkICvXv3Zty4cRw+fLjZ8uLiYvLy8jyqzns+n48Hfvw0vy7Mp6aqEoCzpz5j68qFTJ33LCPvn+JxhV3XnXfeyXvvvdc4jS0iIgK/3w+gMO6AkJ/AM/Uvk8uBeUAc8K/AfGvt6VDvq6fbvn072dnZ5ObmMm7cONatW8fkyZM5efIkAwYMACAjI4OFCxeydu1aj6v1zpjUDPblr+dfCn/Bn6Rmkrd0Lj+c8ih//uhcr0tzUnV1NadOnWq8ff7551y4cIHKykouXrxIbGwsffr0oX///vTu3ZvLly8D9T3l9PR0KioqGD16tMe/RdcTjtkUzwA/AeYApcBK4B1jTJK19tsw7K/Hevnll5k3bx5ZWVkA5ObmsnfvXrZs2cLixYsBmDRpEhUVFXz22WcMGzbMy3I94/dHkPrYU+zZ+hIfH9jN4HtG8Mhf/b3XZTnDWsunn35KIBCgsLCQmpqaVtc/f/58i8uOHz/OtGnTrhm6kBtr9zCFMSbWGPMLY0yVMeZLY8zfGGPeN8asa+gVLwJWWWsLrbVHgSeA7wLTQlp5D3fp0iVKSkpITU1tbPP5fKSmpvLRRx81tvXq1YsHH3yQQCDgRZnOGJOawaWaajCGJ//uFV0hBpSVlbFx40buu+8+Zs2axZtvvnnDIL6R0tJS1q5dy6RJk5g9ezY7d+6kqqoqRBV3bx3pGb8ITAQygK+A1cAfA58CdwEDgf1XVrbWXjDGFAPjgTfbsoOe+iEjV8bb2uL8+fPU1dURHx/frD0+Pv6aE3YZGRls2rSJJUuWtLi97n7Md7xS3xOuvvB7jANB7OXxLisrY82aNRQVFV13eVxcHGPHjiUxMZHExESGDBlCv3796NWrF36/n9raWi5evEh+fj6bNm1qcT8lJSWUlJSwdOlSnn76aebOnUtMTEyH6+6qz9G2/l+3K4yNMbcAc4HZ1tqihrY5wO8aVhnY8LPiqodWNFl29TZ7Ab2atrX2B+7OnnrqqbBsNy0tjaysLM6fP0///v2vu85rr70Wln23SWJ4T6Lt3foSx4oPkv2zXfws53E++uftTJj2ROPyirIzrP3Jo0Tf0pfeMbF8Xf4F3/tBEovW7whbTZ093ikpKe1+THV1Nbm5ubz++uvXLBs8eDAzZ84kPT298XxDSyIjI4mJiaG4uBifz4e1lqSkJHbs2MHx48cpLCwkPz+/2WNeffVV8vLyeOGFF0hPT+/QMIanz9FOaOv/dXt7xncDUUDxlQZr7e+NMSfbuZ2m/hZoNoC3cuXKTmyu62pPGPfv3x+/309FRfPXvYqKCgYObP66V1paSlxcHHFxcS1uz8tjvjg/fGH84d5tHNjxOgt++ituvzuJlOlZFG3P40//4sf4I+ovTIgffDcJf5TM1HnP8t3v38uqOT9i/gtvhK0m6Pzxbk8YW2spKCi47jujrKwsMjIyuOeee9q1//Lycj7++GMAjDFkZmZijGHo0KEMHTqUnJwcPvzwQ3bt2sW7774L1Pdsc3Jy2Lp1K8uXL2/3OYyumgvhCuMbOdfwMx74skl7PPXDGNfzj8DLTRu2bdt2QVfwtC4qKorRo0dTVFTEtGnTgPo5tUVFRSxYsKDZuoFAgLS0NCIiWv5zv/XWW+Est1W/6dwwZYuOFR9kx4bneXLpK9yVNAqACRlPcGD7Zg6/9zbjH/rLxnUrzn7OgDu+z6VvawgGg/SK7vjb6ba4Wce7urqaxYsXs3///mbt06dPZ9GiRS2+U7qRPXv24PP5CAaD+Hw+0tLSmi2PjIxk4sSJTJw4kSNHjvD88883Dp8dP36cGTNmsGTJEmbPnt3mXrKXz9Gbob1hfAaoBcYBZQDGmH5AIvAB9bMnzgGTaAhfY0zfhvWvO/Zgrb0IXGx/6ZKdnc2cOXMYM2YMY8eOZd26dVRXVzfOrrgiEAjw3HPPtbqt8ePHh7PUVv0mDN8OXXbq39m6YgEZ8xYz8s8mN7ZH39KXCZlPsn/bJsY9OB2f38+3/1dFRGQUEZFRfHHmCPGD7w55PVfr7PFuy4U8paWlZGVlNXv3NGLECJYtW8bQoUM7vG9rLbt27SIYDOL3+5kwYQL9+vVrcf2RI0eyc+dOdu/e3TjLB2D16tUcPXqUFStWEB0dfcP9evkcvRnaFcbW2ipjzM+BF40x/039Cbx/AIINy60xZh2w1Bhzmj9MbfsvoCCEdQvw2GOP8fXXX7Ns2TLOnTtHcnIy+/bta3ZSr7S0lJMnTzJlSs+6uGFw4nB+uvfYdZelZ2WTnvWHy3jPfXGagXf+AICKsv9kwPfuuik1htv69eubBfHy5cuZMWNGp6edHTt2jLKyMqB+6OHKO7PW+Hw+MjIySE1NZdWqVRQUFAD1Pez777+fqVOndqqm7qAjwxQ5wC3AbuB/gZeA7zRZvgaIBTZTf9HHIWCK5hiHx4IFC64ZlmgqEAiQkpJCnz59bmJVXcuXvz3NoIREAKJ6x3Ci5BDVF/6H2O+03NvrClasWMHp06f55ptvyM3NZfjw4SHZbkFBAX6/n7q6OmJiYto1fh0bG8vq1asZPnw4K1euZObMmTz88MMhqaura3cYW2urgMcbbgAYY9KbLLfAsoabeCwQCPDII494XYbTmo4dJ094iOQJD3lYTej07duXzZs3Ex0dza233hqSbdbW1rJ7927q6urw+/2kp6e3+9JnYwyzZs0iOTmZIUOG6AKRBvo8426upbmk0jPcfvvtId3eoUOHqKys/4yPtg5RtCQpKSlEVXUP3s9+lzZLSEhg0aJFXpchPVhhYWHjRQyDBg1i1KhRHlfUfYSkZ2ytTQnFdqR1CmPxUmVlJUVFRdTV1eHz+RrnFktoqGcsIm3yzjvvNH5CWzAY1Im3ENOYsYi0ydtvv93YEx42bFi7v+hAWqeesYjc0FdffcUnn3xC/WQpyMzM9Lii7kdhLCI3dNtttzF27Fig/hs9etpFRDeDhilE5Ib8fj9vvPEGZ8+eJSIiotXLn6VjFMYi0mZ33HGH1yV0WxqmEBFxgMJYRMQBCmMREQcojEVEHGCuzBt0jJNFiYh0QJuuGVfPWETEAQpjEREHKIxFRBygMBYRcYDCWETEAQpjEREHKIxFRBygMBYRcYDCWETEAQpjEREHKIxFRBygMBYRcYDCWETEAQpjEREHKIxFRBygMBYRcYDCWETEAQpjEREHRHhdQAva9DUlIiLdhXrGIiIOUBiLiDhAYSwi4gCFsYiIAxTGIiIOUBiLiDhAYSwi4gCFsYiIAxTGIiIO+H+N0oaYSOnwCwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "t1_schedule = t1_sched(times=[1e-6])\n", "t1_schedule.plot_circuit_diagram();" ] }, { "cell_type": "markdown", "id": "589c28b8", "metadata": {}, "source": [ "For displaying the pulse diagram and timing table, the schedule first needs to get timing information for each operation in the schedule. This is achieved by compiling the schedule using {class}`~quantify_scheduler.backends.graph_compilation.SerialCompiler`. Please note that below in section {ref}`run_experiment`, the compilation is handled by {class}`~quantify_core.measurement.control.MeasurementControl` internally; it is done here only to enable displaying the timing table and pulse diagram.\n", "\n", "```{admonition} Compiling to Hardware\n", "More information on compilation can be found in {ref}`sec-tutorial-compiling`.\n", "```" ] }, { "cell_type": "code", "execution_count": 10, "id": "47d6f915", "metadata": {}, "outputs": [], "source": [ "from quantify_scheduler.backends.graph_compilation import SerialCompiler\n", "\n", "compiler = SerialCompiler(name=\"compiler\", quantum_device=single_qubit_device)\n", "compiled_schedule = compiler.compile(schedule=t1_schedule)" ] }, { "cell_type": "markdown", "id": "42627c9d", "metadata": {}, "source": [ "Each operation is compiled into pulses that can be viewed and inspected via the {meth}`~quantify_scheduler.schedules.schedule.ScheduleBase.plot_pulse_diagram` method." ] }, { "cell_type": "code", "execution_count": 11, "id": "9f985e7b", "metadata": {}, "outputs": [ { "data": { "text/html": [ "