{ "cells": [ { "cell_type": "markdown", "id": "da5198c6", "metadata": {}, "source": [ "(sec-dataset-advanced-examples)=\n", "# Quantify dataset - advanced examples\n", "\n", "```{seealso}\n", "The complete source code of this tutorial can be found in\n", "\n", "{nb-download}`Quantify dataset - advanced examples.ipynb`\n", "```\n", "\n", "Here we will explore a few advanced usages of the Quantify dataset and how it can\n", "accommodate them." ] }, { "cell_type": "code", "execution_count": 1, "id": "64643c33", "metadata": { "mystnb": { "code_prompt_show": "Imports and auxiliary utilities" }, "tags": [ "hide-cell" ] }, "outputs": [], "source": [ "from pathlib import Path\n", "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import xarray as xr\n", "from rich import pretty\n", "\n", "from quantify_core.analysis.calibration import rotate_to_calibrated_axis\n", "from quantify_core.analysis.fitting_models import exp_decay_func\n", "from quantify_core.data import handling as dh\n", "from quantify_core.utilities import dataset_examples\n", "from quantify_core.utilities.dataset_examples import (\n", " mk_nested_mc_dataset,\n", " mk_shots_from_probabilities,\n", " mk_surface7_cyles_dataset,\n", ")\n", "from quantify_core.utilities.examples_support import (\n", " mk_iq_shots,\n", " round_trip_dataset,\n", ")\n", "from quantify_core.utilities.inspect_utils import display_source_code\n", "\n", "pretty.install()\n", "\n", "dh.set_datadir(Path.home() / \"quantify-data\") # change me!" ] }, { "cell_type": "markdown", "id": "b075ee74", "metadata": {}, "source": [ "## Dataset for an \"unstructured\" experiment\n", "\n", "Let's take consider a Surface Code experiment, in particular the one portrayed in\n", "Fig. 4b from one of the papers from DiCarlo Lab {cite}`marques_logical_qubit_2021`.\n", "\n", "For simplicity, we will not use exactly the same schedule, because what matters here\n", "are the measurements. It is difficult to deal with the results of these measurements\n", "because we have a few repeating cycles followed by a final measurement that leaves the\n", "overall dataset \"unstructured\".\n", "\n", "```{figure} /images/surface-7-sched.png\n", ":width: 100%\n", "```\n", "\n", "``````{admonition} Source code for generating this schedule and visualizing it\n", ":class: dropdown, info\n", "\n", "If you want to create and visualize the schedule above using `quantify-scheduler`,\n", "you can use this code:\n", "\n", "```{code-block} python\n", "from quantify_scheduler import Schedule\n", "from quantify_scheduler.operations.gate_library import CZ, Y90, Measure, Reset, X\n", "from quantify_scheduler.visualization.circuit_diagram import circuit_diagram_matplotlib\n", "\n", "def mk_surface7_sched(num_cycles: int = 3):\n", " \"\"\"Generates a schedule with some of the feature of a Surface 7 experiment as\n", " portrayed in Fig. 4b of :cite:`marques_logical_qubit_2021`.\n", "\n", " Parameters\n", " ----------\n", " num_cycles\n", " The number of times to repeat the main cycle.\n", "\n", " Returns\n", " -------\n", " :\n", " A schedule similar to a Surface 7 dance.\n", " \"\"\"\n", "\n", " sched = Schedule(\"S7 dance\")\n", "\n", " q_d1, q_d2, q_d3, q_d4 = [f\"D{i}\" for i in range(1, 5)]\n", " q_a1, q_a2, q_a3 = [f\"A{i}\" for i in range(1, 4)]\n", " all_qubits = q_d1, q_d2, q_d3, q_d4, q_a1, q_a2, q_a3\n", "\n", " sched.add(Reset(*all_qubits))\n", "\n", " for cycle in range(num_cycles):\n", " sched.add(Y90(q_d1))\n", " for qubit in [q_d2, q_d3, q_d4]:\n", " sched.add(Y90(qubit), ref_pt=\"start\", rel_time=0)\n", " sched.add(Y90(q_a2), ref_pt=\"start\", rel_time=0)\n", "\n", " for qubit in [q_d2, q_d1, q_d4, q_d3]:\n", " sched.add(CZ(qC=qubit, qT=q_a2))\n", "\n", " sched.add(Y90(q_d1))\n", " for qubit in [q_d2, q_d3, q_d4]:\n", " sched.add(Y90(qubit), ref_pt=\"start\", rel_time=0)\n", " sched.add(Y90(q_a2), ref_pt=\"start\", rel_time=0)\n", "\n", " sched.add(Y90(q_a1), ref_pt=\"end\", rel_time=0)\n", " sched.add(Y90(q_a3), ref_pt=\"start\", rel_time=0)\n", "\n", " sched.add(CZ(qC=q_d1, qT=q_a1))\n", " sched.add(CZ(qC=q_d2, qT=q_a3))\n", " sched.add(CZ(qC=q_d3, qT=q_a1))\n", " sched.add(CZ(qC=q_d4, qT=q_a3))\n", "\n", " sched.add(Y90(q_a1), ref_pt=\"end\", rel_time=0)\n", " sched.add(Y90(q_a3), ref_pt=\"start\", rel_time=0)\n", "\n", " sched.add(Measure(q_a2, acq_index=cycle))\n", " for qubit in (q_a1, q_a3):\n", " sched.add(Measure(qubit, acq_index=cycle), ref_pt=\"start\", rel_time=0)\n", "\n", " for qubit in [q_d1, q_d2, q_d3, q_d4]:\n", " sched.add(X(qubit), ref_pt=\"start\", rel_time=0)\n", "\n", " # final measurements\n", "\n", " sched.add(Measure(*all_qubits[:4], acq_index=0), ref_pt=\"end\", rel_time=0)\n", "\n", " return sched\n", "\n", "sched = mk_surface7_sched(num_cycles=3)\n", "f, ax = circuit_diagram_matplotlib(sched)\n", "f.set_figwidth(30)\n", "```\n", "``````\n", "\n", "How do we store all the shots for this measurement?\n", "We might want this because, e.g., we know we have an issue with leakage to the second\n", "excited state of a transmon and we would like to be able to store and inspect raw data.\n", "\n", "To support such use-cases we will have a dimension in the dataset for the repeating cycles\n", "and one extra dimension for the final measurement." ] }, { "cell_type": "code", "execution_count": 2, "id": "d2f2ddcf", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n" ], "text/plain": [] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "def mk_iq_shots(\n",
" num_shots: int = 128,\n",
" sigmas: Union[Tuple[float], NDArray[np.float64]] = (0.1, 0.1),\n",
" centers: Union[Tuple[complex], NDArray[np.complex128]] = (-0.2 + 0.65j, 0.7 + 4j),\n",
" probabilities: Union[Tuple[float], NDArray[np.float64]] = (0.4, 0.6),\n",
" seed: Union[int, None] = 112233,\n",
") -> NDArray:\n",
" """\n",
" Generate clusters of (I + 1j*Q) points with a Gaussian distribution.\n",
"\n",
" Utility to mock the data coming from qubit readout experiments.\n",
" Clusters are centered around ``centers`` and data points are distributed between\n",
" them according to ``probabilities``.\n",
"\n",
" .. seealso:: :ref:`howto-utilities-examples-ssro`\n",
"\n",
" Parameters\n",
" ----------\n",
" num_shots\n",
" The number of shot to generate.\n",
" sigma\n",
" The sigma of the Gaussian distribution used for both real and imaginary parts.\n",
" centers\n",
" The center of each cluster on the imaginary plane.\n",
" probabilities\n",
" The probabilities of each cluster being randomly selected for each shot.\n",
" seed\n",
" Random number generator seed passed to ``numpy.random.default_rng``.\n",
" """\n",
" if not len(sigmas) == len(centers) == len(probabilities):\n",
" raise ValueError(\n",
" f"Incorrect input. sigmas={sigmas}, centers={centers} and "\n",
" f"probabilities={probabilities} must have the same length."\n",
" )\n",
"\n",
" rng = np.random.default_rng(seed=seed)\n",
"\n",
" cluster_indices = tuple(range(len(centers)))\n",
" choices = rng.choice(a=cluster_indices, size=num_shots, p=probabilities)\n",
"\n",
" shots = []\n",
" for idx in cluster_indices:\n",
" num_shots_this_cluster = np.sum(choices == idx)\n",
" i_data = rng.normal(\n",
" loc=centers[idx].real,\n",
" scale=sigmas[idx],\n",
" size=num_shots_this_cluster,\n",
" )\n",
" q_data = rng.normal(\n",
" loc=centers[idx].imag,\n",
" scale=sigmas[idx],\n",
" size=num_shots_this_cluster,\n",
" )\n",
" shots.append(i_data + 1j * q_data)\n",
" return np.concatenate(shots)\n",
"
def mk_shots_from_probabilities(probabilities: Union[np.ndarray, list], **kwargs):\n",
" """Generates multiple shots for a list of probabilities assuming two states.\n",
"\n",
" Parameters\n",
" ----------\n",
" probabilities\n",
" The list/array of the probabilities of one of the states.\n",
" **kwargs\n",
" Keyword arguments passed to\n",
" :func:`~quantify_core.utilities.examples_support.mk_iq_shots`.\n",
"\n",
" Returns\n",
" -------\n",
" :\n",
" Array containing the shots. Shape: (num_shots, len(probabilities)).\n",
" """\n",
"\n",
" shots = np.array(\n",
" tuple(\n",
" mk_iq_shots(probabilities=[prob, 1 - prob], **kwargs)\n",
" for prob in probabilities\n",
" )\n",
" ).T\n",
"\n",
" return shots\n",
"
def mk_surface7_cyles_dataset(num_cycles: int = 3, **kwargs) -> xr.Dataset:\n",
" """\n",
" See also :func:`mk_surface7_sched` inlined in the documentation as an example in:\n",
" :ref:`sec-dataset-advanced-examples`\n",
"\n",
"\n",
"\n",
" Parameters\n",
" ----------\n",
" num_cycles\n",
" The number of repeating cycles before the final measurement.\n",
" **kwargs\n",
" Keyword arguments passed to :func:`~.mk_shots_from_probabilities`.\n",
" """\n",
"\n",
" cycles = range(num_cycles)\n",
"\n",
" mock_data = mk_shots_from_probabilities(\n",
" probabilities=[np.random.random() for _ in cycles], **kwargs\n",
" )\n",
"\n",
" mock_data_final = mk_shots_from_probabilities(\n",
" probabilities=[np.random.random()], **kwargs\n",
" )\n",
"\n",
" # %%\n",
" data_vars = {}\n",
"\n",
" # NB same random data is used for all qubits only for the simplicity of the mock!\n",
" for qubit in (f"A{i}" for i in range(3)):\n",
" data_vars[f"{qubit}_shots"] = (\n",
" ("repetitions", "dim_cycle"),\n",
" mock_data,\n",
" mk_main_var_attrs(\n",
" unit="V", long_name=f"IQ amplitude {qubit}", has_repetitions=True\n",
" ),\n",
" )\n",
"\n",
" for qubit in (f"D{i}" for i in range(4)):\n",
" data_vars[f"{qubit}_shots"] = (\n",
" ("repetitions", "dim_final"),\n",
" mock_data_final,\n",
" mk_main_var_attrs(\n",
" unit="V", long_name=f"IQ amplitude {qubit}", has_repetitions=True\n",
" ),\n",
" )\n",
"\n",
" cycle_attrs = mk_main_coord_attrs(long_name="Surface code cycle number")\n",
" final_msmt_attrs = mk_main_coord_attrs(long_name="Final measurement")\n",
" coords = dict(\n",
" cycle=("dim_cycle", cycles, cycle_attrs),\n",
" final_msmt=("dim_final", [0], final_msmt_attrs),\n",
" )\n",
"\n",
" dataset = xr.Dataset(\n",
" data_vars=data_vars,\n",
" coords=coords,\n",
" attrs=mk_dataset_attrs(),\n",
" )\n",
"\n",
" return dataset\n",
"
<xarray.Dataset> Size: 27kB\n", "Dimensions: (repetitions: 128, dim_cycle: 3, dim_final: 1)\n", "Coordinates:\n", " cycle (dim_cycle) int64 24B 0 1 2\n", " final_msmt (dim_final) int64 8B 0\n", "Dimensions without coordinates: repetitions, dim_cycle, dim_final\n", "Data variables:\n", " A0_shots (repetitions, dim_cycle) complex128 6kB (-0.23630343679164473...\n", " A1_shots (repetitions, dim_cycle) complex128 6kB (-0.23630343679164473...\n", " A2_shots (repetitions, dim_cycle) complex128 6kB (-0.23630343679164473...\n", " D0_shots (repetitions, dim_final) complex128 2kB (-0.23630343679164473...\n", " D1_shots (repetitions, dim_final) complex128 2kB (-0.23630343679164473...\n", " D2_shots (repetitions, dim_final) complex128 2kB (-0.23630343679164473...\n", " D3_shots (repetitions, dim_final) complex128 2kB (-0.23630343679164473...\n", "Attributes:\n", " tuid: 20241014-175517-668-824d0c\n", " dataset_name: \n", " dataset_state: None\n", " timestamp_start: None\n", " timestamp_end: None\n", " quantify_dataset_version: 2.0.0\n", " software_versions: {}\n", " relationships: []\n", " json_serialize_exclude: []
<xarray.Dataset> Size: 27kB\n", "Dimensions: (repetitions: 128, cycle: 3, final_msmt: 1)\n", "Coordinates:\n", " * cycle (cycle) int64 24B 0 1 2\n", " * final_msmt (final_msmt) int64 8B 0\n", "Dimensions without coordinates: repetitions\n", "Data variables:\n", " A0_shots (repetitions, cycle) complex128 6kB (-0.23630343679164473+0.7...\n", " A1_shots (repetitions, cycle) complex128 6kB (-0.23630343679164473+0.7...\n", " A2_shots (repetitions, cycle) complex128 6kB (-0.23630343679164473+0.7...\n", " D0_shots (repetitions, final_msmt) complex128 2kB (-0.2363034367916447...\n", " D1_shots (repetitions, final_msmt) complex128 2kB (-0.2363034367916447...\n", " D2_shots (repetitions, final_msmt) complex128 2kB (-0.2363034367916447...\n", " D3_shots (repetitions, final_msmt) complex128 2kB (-0.2363034367916447...\n", "Attributes:\n", " tuid: 20241014-175517-668-824d0c\n", " dataset_name: \n", " dataset_state: None\n", " timestamp_start: None\n", " timestamp_end: None\n", " quantify_dataset_version: 2.0.0\n", " software_versions: {}\n", " relationships: []\n", " json_serialize_exclude: []
def mk_nested_mc_dataset(\n",
" num_points: int = 12,\n",
" flux_bias_min_max: tuple = (-0.04, 0.04),\n",
" resonator_freqs_min_max: tuple = (7e9, 7.3e9),\n",
" qubit_freqs_min_max: tuple = (4.5e9, 5.0e9),\n",
" t1_values_min_max: tuple = (20e-6, 50e-6),\n",
" seed: Optional[int] = 112233,\n",
") -> xr.Dataset:\n",
" """\n",
" Generates a dataset with dataset references and several coordinates that serve to\n",
" index the same variables.\n",
"\n",
" Note that the each value for ``resonator_freqs``, ``qubit_freqs`` and ``t1_values``\n",
" would have been extracted from other dataset corresponding to individual experiments\n",
" with their own dataset.\n",
"\n",
" Parameters\n",
" ----------\n",
" num_points\n",
" Number of datapoints to generate (used for all variables/coordinates).\n",
" flux_bias_min_max\n",
" Range for mock values.\n",
" resonator_freqs_min_max\n",
" Range for mock values.\n",
" qubit_freqs_min_max\n",
" Range for mock values.\n",
" t1_values_min_max\n",
" Range for mock random values.\n",
" seed\n",
" Random number generator seed passed to ``numpy.random.default_rng``.\n",
" """\n",
" rng = np.random.default_rng(seed=seed) # random number generator\n",
"\n",
" flux_bias_vals = np.linspace(*flux_bias_min_max, num_points)\n",
" resonator_freqs = np.linspace(*resonator_freqs_min_max, num_points)\n",
" qubit_freqs = np.linspace(*qubit_freqs_min_max, num_points)\n",
" t1_values = rng.uniform(*t1_values_min_max, num_points)\n",
"\n",
" resonator_freq_tuids = [dh.gen_tuid() for _ in range(num_points)]\n",
" qubit_freq_tuids = [dh.gen_tuid() for _ in range(num_points)]\n",
" t1_tuids = [dh.gen_tuid() for _ in range(num_points)]\n",
"\n",
" coords = dict(\n",
" flux_bias=(\n",
" "main_dim",\n",
" flux_bias_vals,\n",
" mk_main_coord_attrs(long_name="Flux bias", unit="A"),\n",
" ),\n",
" resonator_freq_tuids=(\n",
" "main_dim",\n",
" resonator_freq_tuids,\n",
" mk_main_coord_attrs(\n",
" long_name="Dataset TUID resonator frequency", is_dataset_ref=True\n",
" ),\n",
" ),\n",
" qubit_freq_tuids=(\n",
" "main_dim",\n",
" qubit_freq_tuids,\n",
" mk_main_coord_attrs(\n",
" long_name="Dataset TUID qubit frequency", is_dataset_ref=True\n",
" ),\n",
" ),\n",
" t1_tuids=(\n",
" "main_dim",\n",
" t1_tuids,\n",
" mk_main_coord_attrs(long_name="Dataset TUID T1", is_dataset_ref=True),\n",
" ),\n",
" )\n",
"\n",
" data_vars = dict(\n",
" resonator_freq=(\n",
" "main_dim",\n",
" resonator_freqs,\n",
" mk_main_var_attrs(long_name="Resonator frequency", unit="Hz"),\n",
" ),\n",
" qubit_freq=(\n",
" "main_dim",\n",
" qubit_freqs,\n",
" mk_main_var_attrs(long_name="Qubit frequency", unit="Hz"),\n",
" ),\n",
" t1=(\n",
" "main_dim",\n",
" t1_values,\n",
" mk_main_var_attrs(long_name="T1", unit="s"),\n",
" ),\n",
" )\n",
" dataset_attrs = mk_dataset_attrs()\n",
"\n",
" dataset = xr.Dataset(data_vars=data_vars, coords=coords, attrs=dataset_attrs)\n",
"\n",
" return dataset\n",
"
<xarray.Dataset> Size: 2kB\n", "Dimensions: (main_dim: 7)\n", "Coordinates:\n", " flux_bias (main_dim) float64 56B -0.04 -0.02667 ... 0.02667 0.04\n", " resonator_freq_tuids (main_dim) <U26 728B '20241014-175518-726-e65fee' ....\n", " qubit_freq_tuids (main_dim) <U26 728B '20241014-175518-727-6a85ba' ....\n", " t1_tuids (main_dim) <U26 728B '20241014-175518-727-cec4c2' ....\n", "Dimensions without coordinates: main_dim\n", "Data variables:\n", " resonator_freq (main_dim) float64 56B 7e+09 7.05e+09 ... 7.3e+09\n", " qubit_freq (main_dim) float64 56B 4.5e+09 4.583e+09 ... 5e+09\n", " t1 (main_dim) float64 56B 4.238e-05 ... 4.154e-05\n", "Attributes:\n", " tuid: 20241014-175518-728-7f46e3\n", " dataset_name: \n", " dataset_state: None\n", " timestamp_start: None\n", " timestamp_end: None\n", " quantify_dataset_version: 2.0.0\n", " software_versions: {}\n", " relationships: []\n", " json_serialize_exclude: []
<xarray.Dataset> Size: 2kB\n", "Dimensions: (main_dim: 7)\n", "Coordinates:\n", " * main_dim (main_dim) object 56B MultiIndex\n", " * flux_bias (main_dim) float64 56B -0.04 -0.02667 ... 0.02667 0.04\n", " * resonator_freq_tuids (main_dim) <U26 728B '20241014-175518-726-e65fee' ....\n", " * qubit_freq_tuids (main_dim) <U26 728B '20241014-175518-727-6a85ba' ....\n", " * t1_tuids (main_dim) <U26 728B '20241014-175518-727-cec4c2' ....\n", "Data variables:\n", " resonator_freq (main_dim) float64 56B 7e+09 7.05e+09 ... 7.3e+09\n", " qubit_freq (main_dim) float64 56B 4.5e+09 4.583e+09 ... 5e+09\n", " t1 (main_dim) float64 56B 4.238e-05 ... 4.154e-05\n", "Attributes:\n", " tuid: 20241014-175518-728-7f46e3\n", " dataset_name: \n", " dataset_state: None\n", " timestamp_start: None\n", " timestamp_end: None\n", " quantify_dataset_version: 2.0.0\n", " software_versions: {}\n", " relationships: []\n", " json_serialize_exclude: []
<xarray.DataArray 'qubit_freq' (main_dim: 1)> Size: 8B\n", "array([4.66666667e+09])\n", "Coordinates:\n", " * main_dim (main_dim) object 8B MultiIndex\n", " * flux_bias (main_dim) float64 8B -0.01333\n", " * resonator_freq_tuids (main_dim) <U26 104B '20241014-175518-726-c80233'\n", " * t1_tuids (main_dim) <U26 104B '20241014-175518-727-296f55'\n", " qubit_freq_tuids <U26 104B '20241014-175518-727-2edb19'\n", "Attributes:\n", " unit: Hz\n", " long_name: Qubit frequency\n", " is_main_var: True\n", " uniformly_spaced: True\n", " grid: True\n", " is_dataset_ref: False\n", " has_repetitions: False\n", " json_serialize_exclude: []
<xarray.DataArray 'qubit_freq' (main_dim: 1)> Size: 8B\n", "array([4.66666667e+09])\n", "Coordinates:\n", " * main_dim (main_dim) object 8B MultiIndex\n", " * flux_bias (main_dim) float64 8B -0.01333\n", " * resonator_freq_tuids (main_dim) <U26 104B '20241014-175518-726-c80233'\n", " * qubit_freq_tuids (main_dim) <U26 104B '20241014-175518-727-2edb19'\n", " t1_tuids <U26 104B '20241014-175518-727-296f55'\n", "Attributes:\n", " unit: Hz\n", " long_name: Qubit frequency\n", " is_main_var: True\n", " uniformly_spaced: True\n", " grid: True\n", " is_dataset_ref: False\n", " has_repetitions: False\n", " json_serialize_exclude: []
<xarray.Dataset> Size: 2kB\n", "Dimensions: (main_dim: 7)\n", "Coordinates:\n", " flux_bias (main_dim) float64 56B -0.04 -0.02667 ... 0.02667 0.04\n", " resonator_freq_tuids (main_dim) <U26 728B '20241014-175518-726-e65fee' ....\n", " qubit_freq_tuids (main_dim) <U26 728B '20241014-175518-727-6a85ba' ....\n", " t1_tuids (main_dim) <U26 728B '20241014-175518-727-cec4c2' ....\n", "Dimensions without coordinates: main_dim\n", "Data variables:\n", " resonator_freq (main_dim) float64 56B 7e+09 7.05e+09 ... 7.3e+09\n", " qubit_freq (main_dim) float64 56B 4.5e+09 4.583e+09 ... 5e+09\n", " t1 (main_dim) float64 56B 4.238e-05 ... 4.154e-05\n", "Attributes:\n", " tuid: 20241014-175518-728-7f46e3\n", " dataset_name: \n", " dataset_state: None\n", " timestamp_start: None\n", " timestamp_end: None\n", " quantify_dataset_version: 2.0.0\n", " software_versions: {}\n", " relationships: []\n", " json_serialize_exclude: []