Custom QuAM Components
To create custom QuAM components, their classes should be defined in a Python module that can be accessed from Python. The reason for this is that otherwise QuAM cannot load QuAM from a JSON file as it cannot determine where the classes are defined. If you already have a Python module that you use for your own QUA code, it is recommended to add QuAM components to that module. If you don't already have such a module, please follow the guide below.
Creating a Custom Python Module
Here we describe how to create a minimal Python module that can be used for your custom QuAM components.
In this example, we will give the top-level folder the name my-quam
and the Python module will be called my_quam
(note the underscore instead of dash).
First create the following folder structure
my-quam
├── my_quam
│ └── __init__.py
│ └── components
│ └── __init__.py
└── pyproject.toml
__init__.py
files should be empty, and pyproject.toml
should have the following contents:
pyproject.toml
[project]
name = "my-quam"
version = "0.1.0"
description = "User QuAM repository"
authors = [{ name = "Jane Doe", email = "jane.doe@quantum-machines.co" }]
requires-python = ">=3.9"
[build-system]
requires = ["setuptools", "setuptools-scm"]
build-backend = "setuptools.build_meta"
[tool.setuptools]
packages = ["my_quam"]
Feel free to modify details such as description
and authors
.
Finally, to install the package, first make sure you're in the correct environment, then navigate to the top-level folder my-quam
and run:
pip install .
from my_quam.components import *
my-quam/my_quam/components
.
Creating a Custom QuAM Component
Once a designated Python module has been chosen / created, it can be populated with a custom component.
We will assume that the newly-created Python module my_quam
is used.
In this example, we will make a basic QuAM component representing a DC gate, with two properties: name
and dc_voltage
:
from typing import Union
from quam.core import QuamComponent, quam_dataclass
@quam_dataclass
class DcGate(QuamComponent):
id: Union[int, str]
dc_voltage: float
from my_quam.components.gates import DcGate
dc_gate = DcGate(id="plunger_gate", dc_voltage=0.43)
A few notes about the above:
- Each QuamComponent inherits from QuamComponent.
- QuAM components are decorated with
@quam_dataclass
, which is a variant of the Python @dataclass.
Reason for @quam_dataclass
instead of @dataclass
Inheriting from a dataclass is not directly possible when the parent class has keyword arguments and the child class does not.
To illustrate this, the following example will raise a TypeError
:
@dataclass
class Parent:
optional_attr: int = 42
@dataclass
class Child(Parent):
required_attr: int
In Python 3.10 and up, this can be solved by adding the kw_only=True
keyword argument:
@dataclass
class Parent:
optional_attr: int = 42
@dataclass(kw_only=True)
class Child(Parent):
required_attr: int
child = Child(required_attr=12) # Note that we now need to explicitly pass keywords
The keyword kw_only
was only introduced in Python 3.10, and so the example above would raise an error in Python <3.10.
However, to ensure QuAM is compatible with Python 3.9 and above, we introduced @quam_dataclass
which fixes this problem:
@quam_dataclass
class Child(Parent):
required_attr: int
An additional benefit is that kw_only=True
is automatically passed along.
From Python 3.10 onwards, @quam_dataclass
is equivalent to @dataclass(kw_only=True, eq=False)
QuAM Component Subclassing
QuAM components can also be subclassed to add functionalities to the parent class.
For example, we now want to combine a DC and AC gate together, where the AC part corresponds to an OPX channel.
To do this, we create a class called AcDcGate
that inherits from both DcGate
and SingleChannel:
from quam.components import SingleChannel
@quam_dataclass
class AcDcGate(DcGate, SingleChannel):
pass
It can be instantiated using
ac_dc_gate = AcDcGate(id="plunger_gate", dc_voltage=0.43, opx_output=("con1", 1))
Notice that the keyword argument opx_output
now also needs to be passed. This is because it's a required argument for SingleChannel.