Skip to content

QUAM Quantum Components API

Welcome to the QUAM Quantum Components API Documentation. The QUAM Quantum Components module provides high-level abstractions for qubits and qubit pairs, enabling gate-level quantum programming. Information can be found in QUAM Gate-Level Operations Documentation in the User Guide.

This section provides detailed API references for quantum component classes—including qubits and qubit pairs—that allow you to work at the gate level rather than the pulse level, bringing your quantum control code closer to quantum circuit thinking.

QuantumComponent

Bases: QuamComponent, ABC

Source code in quam/components/quantum_components/quantum_component.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@quam_dataclass
class QuantumComponent(QuamComponent, ABC):
    id: Union[str, int]
    macros: Dict[str, BaseMacro] = field(default_factory=dict)

    @property
    @abstractmethod
    def name(self) -> str:
        pass

    def apply(self, operation: str, *args, **kwargs) -> Any:
        operation_obj = self.get_macros()[operation]
        return operation_obj.apply(*args, **kwargs)

    @staticmethod
    def register_macro(func: T) -> T:
        """Decorator to register a method as a macro entry point"""
        return cast(T, method_macro(func))

    def _get_method_macros(self) -> Dict[str, method_macro]:
        return dict(
            inspect.getmembers(self, predicate=lambda x: isinstance(x, method_macro))
        )

    def get_macros(self) -> Dict[str, BaseMacro]:
        return {**self.macros, **self._get_method_macros()}

register_macro(func) staticmethod

Decorator to register a method as a macro entry point

Source code in quam/components/quantum_components/quantum_component.py
28
29
30
31
@staticmethod
def register_macro(func: T) -> T:
    """Decorator to register a method as a macro entry point"""
    return cast(T, method_macro(func))

Qubit

Bases: QuantumComponent

Source code in quam/components/quantum_components/qubit.py
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
@quam_dataclass
class Qubit(QuantumComponent):
    id: Union[str, int] = "#./inferred_id"
    macros: Dict[str, MacroType] = field(default_factory=dict)

    @property
    def inferred_id(self) -> Union[str, int]:
        if not str_ref.is_reference(self.get_raw_value("id")):
            return self.id
        elif self.parent is not None:
            name = self.parent.get_attr_name(self)
            return name
        else:
            raise AttributeError(
                f"Cannot infer id of {self} because it is not attached to a parent"
            )

    @property
    def name(self) -> str:
        """Returns the name of the qubit"""
        return self.id if isinstance(self.id, str) else f"q{self.id}"

    @property
    def channels(self) -> Dict[str, Channel]:
        """Returns a dictionary of all channels of the qubit"""
        return {
            key: val
            for key, val in self.get_attrs(
                follow_references=True, include_defaults=True
            ).items()
            if isinstance(val, Channel)
        }

    def get_pulse(self, pulse_name: str) -> Pulse:
        """Returns the pulse with the given name

        Goes through all channels and returns the unique pulse with the given name.

        Raises a ValueError if the pulse is not found or if there are multiple pulses
        with the same name.
        """
        pulses = [
            pulse
            for channel in self.channels.values()
            for key, pulse in channel.operations.items()
            if key == pulse_name
        ]
        if len(pulses) == 0:
            raise ValueError(f"Pulse {pulse_name} not found")
        elif len(pulses) > 1:
            raise ValueError(f"Pulse {pulse_name} is not unique")
        else:
            return pulses[0]

    @QuantumComponent.register_macro
    def align(
        self,
        other_qubits: Optional[Union["Qubit", Iterable["Qubit"]]] = None,
        *args: "Qubit",
    ):
        """Aligns the execution of all channels of this qubit and all other qubits"""
        quantum_components = [self]

        if isinstance(other_qubits, Qubit):
            quantum_components.append(other_qubits)
        elif isinstance(other_qubits, Iterable):
            quantum_components.extend(other_qubits)
        elif other_qubits is not None:
            raise ValueError(f"Invalid type for other_qubits: {type(other_qubits)}")

        if args:
            assert all(isinstance(arg, Qubit) for arg in args)
            quantum_components.extend(args)

        channel_names = {
            ch.name for qubit in quantum_components for ch in qubit.channels.values()
        }

        align(*channel_names)

    def __matmul__(self, other):  # TODO Add QubitPair return type
        """Allows access to qubit pairs using the '@' operator, e.g. (q1 @ q2)"""
        if not isinstance(other, Qubit):
            raise ValueError(
                "Cannot create a qubit pair (q1 @ q2) with a non-qubit object, "
                f"where q1={self} and q2={other}"
            )

        if self is other:
            raise ValueError(
                "Cannot create a qubit pair with same qubit (q1 @ q1), where q1={self}"
            )

        root_quam = self.get_root()

        if root_quam is None:
            raise AttributeError(
                "Qubit pairs not found in the root component. "
                "Please add a 'qubit_pairs' attribute to the root component."
            )

        if not hasattr(root_quam, "qubit_pairs"):
            raise AttributeError(
                "Qubit pairs not found in the root component. "
                "Please add a 'qubit_pairs' attribute to the root component."
            )

        if isinstance(root_quam.qubit_pairs, UserDict):
            qubit_pairs = root_quam.qubit_pairs.values()
        else:
            qubit_pairs = root_quam.qubit_pairs

        for qubit_pair in qubit_pairs:
            if qubit_pair.qubit_control is self and qubit_pair.qubit_target is other:
                return qubit_pair
        else:
            raise ValueError(
                f"Qubit pair not found: qubit_control={self.name}, "
                f"qubit_target={other.name}"
            )

channels property

Returns a dictionary of all channels of the qubit

name property

Returns the name of the qubit

__matmul__(other)

Allows access to qubit pairs using the '@' operator, e.g. (q1 @ q2)

Source code in quam/components/quantum_components/qubit.py
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def __matmul__(self, other):  # TODO Add QubitPair return type
    """Allows access to qubit pairs using the '@' operator, e.g. (q1 @ q2)"""
    if not isinstance(other, Qubit):
        raise ValueError(
            "Cannot create a qubit pair (q1 @ q2) with a non-qubit object, "
            f"where q1={self} and q2={other}"
        )

    if self is other:
        raise ValueError(
            "Cannot create a qubit pair with same qubit (q1 @ q1), where q1={self}"
        )

    root_quam = self.get_root()

    if root_quam is None:
        raise AttributeError(
            "Qubit pairs not found in the root component. "
            "Please add a 'qubit_pairs' attribute to the root component."
        )

    if not hasattr(root_quam, "qubit_pairs"):
        raise AttributeError(
            "Qubit pairs not found in the root component. "
            "Please add a 'qubit_pairs' attribute to the root component."
        )

    if isinstance(root_quam.qubit_pairs, UserDict):
        qubit_pairs = root_quam.qubit_pairs.values()
    else:
        qubit_pairs = root_quam.qubit_pairs

    for qubit_pair in qubit_pairs:
        if qubit_pair.qubit_control is self and qubit_pair.qubit_target is other:
            return qubit_pair
    else:
        raise ValueError(
            f"Qubit pair not found: qubit_control={self.name}, "
            f"qubit_target={other.name}"
        )

align(other_qubits=None, *args)

Aligns the execution of all channels of this qubit and all other qubits

Source code in quam/components/quantum_components/qubit.py
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
@QuantumComponent.register_macro
def align(
    self,
    other_qubits: Optional[Union["Qubit", Iterable["Qubit"]]] = None,
    *args: "Qubit",
):
    """Aligns the execution of all channels of this qubit and all other qubits"""
    quantum_components = [self]

    if isinstance(other_qubits, Qubit):
        quantum_components.append(other_qubits)
    elif isinstance(other_qubits, Iterable):
        quantum_components.extend(other_qubits)
    elif other_qubits is not None:
        raise ValueError(f"Invalid type for other_qubits: {type(other_qubits)}")

    if args:
        assert all(isinstance(arg, Qubit) for arg in args)
        quantum_components.extend(args)

    channel_names = {
        ch.name for qubit in quantum_components for ch in qubit.channels.values()
    }

    align(*channel_names)

get_pulse(pulse_name)

Returns the pulse with the given name

Goes through all channels and returns the unique pulse with the given name.

Raises a ValueError if the pulse is not found or if there are multiple pulses with the same name.

Source code in quam/components/quantum_components/qubit.py
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
def get_pulse(self, pulse_name: str) -> Pulse:
    """Returns the pulse with the given name

    Goes through all channels and returns the unique pulse with the given name.

    Raises a ValueError if the pulse is not found or if there are multiple pulses
    with the same name.
    """
    pulses = [
        pulse
        for channel in self.channels.values()
        for key, pulse in channel.operations.items()
        if key == pulse_name
    ]
    if len(pulses) == 0:
        raise ValueError(f"Pulse {pulse_name} not found")
    elif len(pulses) > 1:
        raise ValueError(f"Pulse {pulse_name} is not unique")
    else:
        return pulses[0]

QubitPair

Bases: QuantumComponent

Source code in quam/components/quantum_components/qubit_pair.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@quam_dataclass
class QubitPair(QuantumComponent):
    id: str = "#./name"
    qubit_control: Qubit
    qubit_target: Qubit
    macros: Dict[str, MacroType] = field(default_factory=dict)

    @property
    def name(self) -> str:
        if not str_ref.is_reference(self.get_raw_value("id")):
            return self.id
        else:
            return f"{self.qubit_control.name}@{self.qubit_target.name}"

    def align(self):
        """Aligns the execution of all channels of both qubits"""
        self.qubit_control.align(self.qubit_target)

align()

Aligns the execution of all channels of both qubits

Source code in quam/components/quantum_components/qubit_pair.py
30
31
32
def align(self):
    """Aligns the execution of all channels of both qubits"""
    self.qubit_control.align(self.qubit_target)