See also

A Jupyter notebook version of this tutorial can be downloaded here.

banner

[1]:
from qblox_scheduler import HardwareAgent
/.venv/lib/python3.14/site-packages/quantify_core/utilities/general.py:13: QCoDeSDeprecationWarning: The `qcodes.utils.helpers` module is deprecated. Please consult the api documentation at https://microsoft.github.io/Qcodes/api/index.html for alternatives.
  from qcodes.utils.helpers import NumpyJSONEncoder

Getting started with quantum dots#

In this notebook we will discuss how to get started with spin qubits using the Qblox platform. The goal of this tutorial is to introduce the basic workflow for controlling and measuring spin qubits, with a focus on guiding you towards describing your laboratory measurement setup with qblox scheduler. This is achieved by providing two configuration files (the hardware configuration and the quantum device configuration files) to the HardwareAgent. This sentence will make sense once you finish this tutorial!

Throughout the tutorial, we will explain the purpose of these configuration files and how they fit into the overall workflow by examining and discussing their most important elements. For clarity, some implementation details are omitted. We consider a simple spin-qubit measurement setup as a starting point for illustrating these concepts.

Let’s look at the two configuration files in detail.

1. Hardware configuration#

This file describes the physical arrangement of your lab, e.g. your measurement rack and your fridge. It consists of three main sections: hardware_description, connectivity, and hardware_options. Let’s go through one by one.

hardware_description: What Qblox instruments do you own?#

The first section lists the Qblox instruments installed in your rack. Here you describe:

  • How many Clusters do you have?

  • In your Cluster, which Modules are installed in which slots?

You can feed this information by defining a dictionary named hardware_description. Here is an example.

[2]:
hardware_description = {
    "cluster0": {
        "instrument_type": "Cluster",
        "modules": {
            "2": {"instrument_type": "QCM"},
            "4": {"instrument_type": "QRM"},
        },
        "ref": "internal",
        "ip": None,
    }
}

Explanation:

  • We have one main chassis defined as cluster0. Its type is Cluster.

  • Out of 20 available slots of the Cluster, two slots are populated:

  • The system uses the Cluster’s internal 10 MHz clock as the reference (ref).

  • ip is set to None - which means that the Dummy Driver will be used. This is perfect for testing your code without the Cluster.

  • If you wish to work with your actual cluster, insert its IP string (e.g., '192.168.0.2') to control your Cluster.

See the Cluster Network and Host Setup for more details on setting up your Cluster(s).

Before closing the section, we will introduce another important concept: a port. Modules interface with the external environment through ports. An input port reads an incoming signal, while an output port generates an outgoing signal: For example, the QCM module has 4 output ports, while the QRM module has 2 input ports and 2 output ports.

You can address a port by <cluster_name>.<module_name>.<port_name>. For example, cluster0.module2.real_output_0.

Now please have a look at your Clusters and Modules. Modify the dictionary based on your own setup and we are good to go!

connectivity: How are the Qblox instruments wired to the quantum dot?#

Here you describe the mapping of a port of a Module to a quantum dot element:

  • The connectivity graph uses the syntax "<cluster_name>.<module_name>.<port_name>", "<port of the quantum dot device>". .. addresses a port of a Module in a Cluster (we already learned this!).

  • Each port controls <port of the quantum dot device>.

We will show how to define the <port of the quantum dot device> in the next section.

Consider the minimal setup as an example: a charge sensor cs0 with a plunger gate (cs0:gt) and the reflectometry readout, multiplxed through the same output. (cs0:res applies the carrier wave for the readout and measures the signal through input 0, reflected back through the tank circuit.)

[3]:
connectivity = {
    "graph": [
        ["cluster0.module4.real_output_0", ["cs0:gt", "cs0:res"]],
    ]
}

Remarks:

  • This example uses 1 cluster (cluster0), which has two Modules (module2 and module4).

  • Among the 8 available ports of the modules, three ports are mapped to the ports of <device_element>.

Well done! Now you can apply a square pulse at the plunger gate of the charge sensor (cs0:gt) instead of referring to cluster0.module2.real_output_0. This is a nice layer of abstraction :)

hardware_options: Other hardware settings.#

Other hardware-related parameters can be stored in the dictionary hardware_options. For example, if you want to specify the attenuation at a ports:

[4]:
hardware_options = (
    {
        "output_att": {
            "cs0:gt": 23,  # dB
        }
    },
)

There are more parameters you can add in, but let’s keep it simple for now.

All done! Just make sure to save these dictionaries in the json or yaml format if you want to use them again. An example file is available at ./dependencies/configs/hw_config.json for you.

2. Quantum device configuration#

This file describes the device under test (DUT), in our case, the quantum dot sample, using elements and edges.

Elements#

DeviceElements (or simply elements) represent the distinct components of a device or sample.

  • element can define physical objects (e.g. a plunger gate) or abstract entities (e.g. a qubit).

  • Each element serves as a container that stores its own specific properties and configuration.

Let’s look at an example.

[5]:
elements = {
    "cs0": {
        "name": "cs0",
        "element_type": "ChargeSensor",
        "ports": {
            "gate": "cs0:gt",
            "readout": "cs0:res",
        },
    },
}
  • We defined an element cs0.

  • An element has properties. In this example, name, element_type, and ports.

  • As a spin qubit user, element_types that we will often use is ChargeSensor and BasicSpinElement.

  • An element has ports. In the above example, cs0 has 2 ports of gt and res.

  • These ports of elements can be mapped to the ports of the Modules using connectivity.

Please define your own elements based on your quantum dot device.

Edges#

Edges describe the interface connecting two DeviceElements. This allows you to represent your quantum dot device as a graph of elements connected via edges.

  • Similar to an element, an edge can define both physical objects and abstract entities.

  • For example, an interdot barrier gate can be defined as an edge as it connects two quantum dot elements.

  • Alternatively, as in the example below, we can define an abstract edge q0_q1 to define the operations between elements q0 and q1.

[6]:
elements["q0"] = {
    "name": "q0",
    "element_type": "BasicSpinElement",
    "ports": {"gate": "q0:gt"},
}
elements["q1"] = {
    "name": "q1",
    "element_type": "BasicSpinElement",
    "ports": {"gate": "q1:gt"},
}

edges = {
    "q0_q1": {
        "name": "q0_q1",
        "parent_element": "q0",
        "child_element": "q1",
        "ports": {"gate": "q0_q1:gt"},
        "edge_type": "SpinEdge",
        "cz": {
            "square_amp": 0.1,
            "square_duration": 1e-6,  # seconds
        },
    },
}
  • Two BasicSpinElements, q0 and q1, are defined for the proof of concept.

  • The ports of the SpinEdge correspond to the interdot barrier q0_q1.

  • It is also recommended to store properties involving both q0 and q1 here, such as CZ gate parameters. There is great flexibility in how to define the elements and edges, but don’t worry too much! The concepts will be more clear in the later tutorials with concrete examples. For now just save relevant properties in the same element or edge for your convenience. Also, don’t forget to save the elements and edges in .json or .yaml format when you are done :)

Hardware Agent#

One final step is to feed the configuration files to the HardwareAgent. Think of the HardwareAgent as the translator between your quantum physics and the instrument rack. It does all the backend management for you and lets you describe quantum gate and pulse sequences in a hardware-agnostic way. This is great in terms of flexibility and scalability.

For your convenience, let’s use the example configuration files at dependencies/configs.

[7]:
hw_agent = HardwareAgent(
    hardware_configuration="./dependencies/configs/tuning_spin_coupled_pair_hardware_config.json",
    quantum_device_configuration="./dependencies/configs/spin_with_psb_device_config_2q.yaml",
)

Bonus tips:

  • You can define an alias for a specific element, e.g. charge_sensor0 = hw_agent.quantum_device.get_element("cs0").

  • The parameters defined inside the configuration files can be modified: charge_sensor0.measure.integration_time = 1e-07

  • The updated parameters can be stored as a file: hw_agent.quantum_device.to_json_file("./dependencies/configs", add_timestamp=True)