Source code for qibolab._core.qubits
from collections.abc import Mapping
from typing import Annotated, Any
from pydantic import ConfigDict, Field
from .identifier import ChannelId, QubitId, TransitionId
from .serialize import Model
__all__ = ["Qubit", "QubitMap"]
DefaultChannelType = Annotated[ChannelId | None, True]
"""If ``True`` the channel is included in the default qubit constructor."""
[docs]
class Qubit(Model):
"""Representation of a physical qubit.
Contains the channel ids used to control the qubit and is instantiated
in the function that creates the corresponding
:class:`qibolab.Platform`
"""
model_config = ConfigDict(frozen=False)
drive: DefaultChannelType = None
"""Ouput channel, to drive the qubit state."""
drive_extra: Annotated[dict[TransitionId | QubitId, ChannelId], False] = Field(
default_factory=dict
)
"""Output channels collection, to drive non-qubit transitions."""
flux: DefaultChannelType = None
"""Output channel, to control the qubit flux."""
probe: DefaultChannelType = None
"""Output channel, to probe the resonator."""
acquisition: DefaultChannelType = None
"""Input channel, to acquire the readout results."""
@property
def channels(self) -> list[ChannelId]:
return [
x
for x in (
[getattr(self, ch) for ch in ["probe", "acquisition", "drive", "flux"]]
+ list(self.drive_extra.values())
)
if x is not None
]
[docs]
@classmethod
def default(
cls, name: QubitId, channels: list[str] | None = None, **kwargs: Any
) -> "Qubit":
"""Create a qubit with default channel names.
Default channel names follow the convention:
'{qubit_name}/{channel_type}'
Args:
name: Name for the qubit to be used for channel ids.
channels: List of channels to add to the qubit.
If ``None`` the following channels will be added:
probe, acquisition, drive and flux.
"""
if channels is None:
channels = [name for name, f in cls.model_fields.items() if f.metadata[0]]
return cls(**{ch: f"{name}/{ch}" for ch in channels}, **kwargs)
[docs]
@classmethod
def coupler(cls, name: QubitId, **kwargs):
"""Create a qubit with default channel names."""
return cls(flux=f"coupler_{name}/flux", **kwargs)
class QubitPair(Model):
"""Represent a two-qubit interaction."""
drive: ChannelId | None = None
"""Output channel, for cross-resonance driving."""
QubitMap = Mapping[QubitId, Qubit]