qibolab package

class qibolab.MetaBackend[source]

Bases: object

Meta-backend class which takes care of loading the qibolab backend.

static load(platform: str)[source]

Loads the backend.

Parameters:

platform (str) – Name of the platform to load.

Returns:

The loaded backend.

Return type:

qibo.backends.abstract.Backend

list_available() dict[source]

Lists all the available qibolab platforms.

class qibolab.QibolabBackend(platform)[source]

Bases: NumpyBackend

property qubits: list[Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])]]

Returns the qubits in the platform.

property connectivity: list[Annotated[tuple[Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])]], BeforeValidator(func=_split, json_schema_input_type=PydanticUndefined), PlainSerializer(func=_join, return_type=PydanticUndefined, when_used=always)]]

Returns the list of connected qubits.

property natives: list[str]

Returns the list of native gates supported by the platform.

apply_gate(gate, state, nqubits)[source]

Apply a gate to state vector.

apply_gate_density_matrix(gate, state, nqubits)[source]

Apply a gate to density matrix.

assign_measurements(measurement_map, readout)[source]

Assigning measurement outcomes to qibo.states.MeasurementResult for each gate.

This allows properly obtaining the measured shots from the qibolab.Readout object obtaned after pulse sequence execution.

Parameters:
  • measurement_map (dict) – Map from each measurement gate to the sequence of readout pulses implementing it.

  • readout (qibolab.Readout) – Readout result object containing the readout measurement shots. This is created in execute_circuit.

execute_circuit(circuit, initial_state=None, nshots=1000)[source]

Executes a quantum circuit.

Parameters:
  • circuit (qibo.models.circuit.Circuit) – Circuit to execute.

  • initial_state (qibo.models.circuit.Circuit) – Circuit to prepare the initial state. If None the default |00...0> state is used.

  • nshots (int) – Number of shots to sample from the experiment.

Returns:

MeasurementOutcomes object containing the results acquired from the execution.

execute_circuits(circuits, initial_states=None, nshots=1000)[source]

Executes multiple quantum circuits with a single communication with the control electronics.

Circuits are unrolled to a single pulse sequence.

Parameters:
  • circuits (list) – List of circuits to execute.

  • initial_states (qibo.models.circuit.Circuit) – Circuit to prepare the initial state. If None the default |00...0> state is used.

  • nshots (int) – Number of shots to sample from the experiment.

Returns:

List of MeasurementOutcomes objects containing the results acquired from the execution of each circuit.

class qibolab.Channel(*, device: str = '', path: str = '')[source]

Bases: Model

Channel to communicate with the qubit.

device: str

Name of the device.

path: str

Physical port addresss within the device.

property port: int
iqout(id_: str) str | None[source]

Extract associated IQ output channel.

This is the identity for each IQ output channel identifier, while it retrieves the associated probe channel for acquisition ones, and None for any other one (essentially, non-RF channels).

The argument is the identifier of the present channel, since it is not stored within the objec itself, as it is only relevant to address it in a collection (and so, out of the scope of the object itself).

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.DcChannel(*, device: str = '', path: str = '')[source]

Bases: Channel

Channel that can be used to send DC pulses.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.IqChannel(*, device: str = '', path: str = '', mixer: str | None = None, lo: str | None = None)[source]

Bases: Channel

Channel that can be used to send IQ pulses.

mixer: str | None

Name of the IQ mixer component corresponding to this channel.

None, if the channel does not have a mixer, or it does not need configuration.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

lo: str | None

Name of the local oscillator component corresponding to this channel.

None, if the channel does not have an LO, or it is not configurable.

class qibolab.AcquisitionChannel(*, device: str = '', path: str = '', twpa_pump: str | None = None, probe: str | None = None)[source]

Bases: Channel

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

twpa_pump: str | None

Name of the TWPA pump component.

None, if there is no TWPA, or it is not configurable.

probe: str | None

Name of the corresponding measure/probe channel.

FIXME: This is temporary solution to be able to relate acquisition channel to corresponding probe channel wherever needed in drivers, until we make acquire channels completely independent, and users start putting explicit acquisition commands in pulse sequence.

class qibolab.DcConfig(*, kind: Literal['dc'] = 'dc', offset: float)[source]

Bases: Config

Configuration for a channel that can be used to send DC pulses (i.e. just envelopes without modulation).

kind: Literal['dc']
offset: float

DC offset/bias of the channel.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.IqConfig(*, kind: Literal['iq'] = 'iq', frequency: float)[source]

Bases: Config

Configuration for an IQ channel.

kind: Literal['iq']
frequency: float

The carrier frequency of the channel.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.AcquisitionConfig(*, kind: Literal['acquisition'] = 'acquisition', delay: float, smearing: float, threshold: float | None = None, iq_angle: float | None = None, kernel: Annotated[ndarray[tuple[Any, ...], dtype[_ScalarT]], PlainValidator(func=ndarray_deserialize, json_schema_input_type=Any), PlainSerializer(func=ndarray_serialize, return_type=str, when_used=always)] | None = None)[source]

Bases: Config

Configuration for acquisition channel.

Currently, in qibolab, acquisition channels are FIXME:

kind: Literal['acquisition']
delay: float

Delay between readout pulse start and acquisition start.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

smearing: float

FIXME:

threshold: float | None

Signal threshold for discriminating ground and excited states.

iq_angle: float | None

Signal angle in the IQ-plane for disciminating ground and excited states.

kernel: Annotated[Annotated[ndarray[tuple[Any, ...], dtype[_ScalarT]], PlainValidator(func=ndarray_deserialize, json_schema_input_type=Any), PlainSerializer(func=ndarray_serialize, return_type=str, when_used=always)] | None, FieldInfo(annotation=NoneType, required=True, repr=False)]

Integration weights to be used when post-processing the acquired signal.

class qibolab.IqMixerConfig(*, kind: Literal['iq-mixer'] = 'iq-mixer', offset_i: float = 0.0, offset_q: float = 0.0, scale_q: float = 1.0, phase_q: float = 0.0)[source]

Bases: Config

Configuration for IQ mixer.

Mixers usually have various imperfections, and one needs to compensate for them. This class holds the compensation configuration.

kind: Literal['iq-mixer']
offset_i: float

DC offset for the I component.

offset_q: float

DC offset for the Q component.

scale_q: float

The relative amplitude scale/factor of the q channel, to account for I-Q amplitude imbalance.

phase_q: float

The phase offset of the q channel, to account for I-Q phase imbalance.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.OscillatorConfig(*, kind: Literal['oscillator'] = 'oscillator', frequency: float, power: float)[source]

Bases: Config

Configuration for an oscillator.

kind: Literal['oscillator']
frequency: float
power: float
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.Config[source]

Bases: Model

Configuration values depot.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.LogConfig(*, kind: Literal['log'] = 'log', path: Path)[source]

Bases: Config

Configuration for logging.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

kind: Literal['log']
path: Path
qibolab.create_dummy() Platform[source]

Create a dummy platform using the dummy instrument.

class qibolab.AcquisitionType(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]

Bases: Enum

Data acquisition from hardware.

DISCRIMINATION = 1

Demodulate, integrate the waveform and discriminate among states based on the voltages.

INTEGRATION = 2

Demodulate and integrate the waveform.

RAW = 3

Acquire the waveform as it is.

class qibolab.AveragingMode(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]

Bases: Enum

Data averaging modes from hardware.

CYCLIC = 1

Better averaging for short timescale noise.

SINGLESHOT = 2

No averaging.

Type:

SINGLESHOT

SEQUENTIAL = 3

Worse averaging for noise[Avoid]

Type:

SEQUENTIAL

property average: bool

Whether an average is performed or not.

class qibolab.ConfigKinds[source]

Bases: object

Registered configuration kinds.

This class is handling the known configuration kinds for deserialization.

Attention

Beware that is managing a global state. This should not be a major issue, as the known configurations should be fixed per run. But prefer avoiding changing them during a single session, unless you are clearly controlling the sequence of all loading operations.

classmethod extend(kinds: Iterable[Any | type[Config]])[source]

Extend the known configuration kinds.

Nested unions are supported (i.e. Union as elements of kinds).

classmethod reset()[source]

Reset known configuration kinds to built-ins.

classmethod registered() list[Any | type[Config]][source]

Retrieve registered configuration kinds.

classmethod adapted() TypeAdapter[source]

Construct tailored pydantic type adapter.

The adapter will be able to directly load all the registered configuration kinds as the appropriate Python objects.

class qibolab.Hardware(*, instruments: ~collections.abc.Mapping[str, ~qibolab._core.instruments.abstract.Instrument], qubits: ~collections.abc.Mapping[~typing.Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], ~qibolab._core.qubits.Qubit], couplers: ~collections.abc.Mapping[~typing.Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], ~qibolab._core.qubits.Qubit] = <factory>)[source]

Bases: Model

Part of the platform that specifies the hardware configuration.

instruments: Mapping[str, Instrument]
qubits: Mapping[Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], Qubit]
couplers: Mapping[Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], Qubit]
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.Parameters(*, settings: ~qibolab._core.parameters.Settings = <factory>, configs: ~typing.Annotated[dict[str, ~qibolab._core.components.configs.Config], ~pydantic.functional_validators.BeforeValidator(func=~qibolab._core.parameters._load_configs, json_schema_input_type=PydanticUndefined), ~pydantic.functional_serializers.PlainSerializer(func=~qibolab._core.parameters._dump_configs, return_type=PydanticUndefined, when_used=always)] = <factory>, native_gates: ~qibolab._core.parameters.NativeGates = <factory>)[source]

Bases: Model

Serializable parameters.

settings: Settings
configs: Annotated[dict[str, Config], BeforeValidator(func=_load_configs, json_schema_input_type=PydanticUndefined), PlainSerializer(func=_dump_configs, return_type=PydanticUndefined, when_used=always)]
native_gates: NativeGates
replace(update: dict[str, Any]) Parameters[source]

Update parameters’ values.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

qibolab.initialize_parameters(hardware: Hardware, natives: set[str] | None = None, pairs: list[str] | None = None) Parameters[source]

Generates default Parameters for a given hardware configuration.

qibolab.create_platform(name: str) Platform[source]

A platform for executing quantum algorithms.

It consists of a quantum processor QPU and a set of controlling instruments.

Parameters:

name (str) – name of the platform.

Returns:

The plaform class.

qibolab.locate_platform(name: str, paths: list[Path] | None = None) Path[source]

Locate platform’s path.

The name corresponds to the name of the folder in which the platform is defined, i.e. the one containing the platform.py file.

If paths are specified, the environment is ignored, and the folder search happens only in the specified paths.

class qibolab.Platform(name: str, parameters: ~qibolab._core.parameters.Parameters, instruments: ~collections.abc.Mapping[str, ~qibolab._core.instruments.abstract.Instrument], qubits: ~collections.abc.Mapping[~typing.Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], ~qibolab._core.qubits.Qubit], couplers: ~collections.abc.Mapping[~typing.Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], ~qibolab._core.qubits.Qubit] = <factory>, resonator_type: ~typing.Literal['2D', '3D'] = '2D', is_connected: bool = False)[source]

Bases: object

Platform for controlling quantum devices.

name: str

Name of the platform.

parameters: Parameters

instruments: Mapping[str, Instrument]

Mapping instrument names to qibolab.instruments.abstract.Instrument objects.

qubits: Mapping[Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], Qubit]

Qubit controllers.

The mapped objects hold the qubit.components.channels.Channel instances required to send pulses addressing the desired qubits.

couplers: Mapping[Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], Qubit]

Coupler controllers.

Fully analogue to qubits. Only the flux channel is expected to be populated in the mapped objects.

resonator_type: Literal['2D', '3D'] = '2D'

Type of resonator (2D or 3D) in the used QPU.

is_connected: bool = False

Flag for whether we are connected to the physical instruments.

property nqubits: int

Total number of usable qubits in the QPU.

property pairs: list[Annotated[tuple[Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])]], BeforeValidator(func=_split, json_schema_input_type=PydanticUndefined), PlainSerializer(func=_join, return_type=PydanticUndefined, when_used=always)]]

Available pairs in thee platform.

property ordered_pairs

List of qubit pairs that are connected in the QPU.

property settings: Settings

Container with default execution settings.

property natives: NativeGates

Native gates containers.

property sampling_rate

Sampling rate of control electronics in giga samples per second (GSps).

property components: set[str]

Names of all components available in the platform.

property channels: dict[str, Channel]

Channels in the platform.

property qubit_channels: dict[str, Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])]]

Channel to qubit map.

property coupler_channels

Channel to coupler map.

config(name: str) Config[source]

Returns configuration of given component.

update(update: dict[str, Any])[source]

Update platform’s parameters.

connect()[source]

Connect to all instruments.

disconnect()[source]

Disconnects from instruments.

termination_handler(signum, frame)[source]
execute(sequences: list[PulseSequence], sweepers: list[list[Sweeper]] | None = None, **options) dict[Annotated[UUID, UuidVersion(uuid_version=4)], ndarray[tuple[Any, ...], dtype[float64]]][source]

Execute pulse sequences.

If any sweeper is passed, the execution is performed for the different values of sweeped parameters.

Returns readout results acquired by after execution.

Example

import numpy as np
from qibolab import Parameter, PulseSequence, Sweeper, create_dummy


platform = create_dummy()
qubit = platform.qubits[0]
natives = platform.natives.single_qubit[0]
sequence = natives.MZ.create_sequence()
parameter_range = np.random.randint(10, size=10)
sweeper = [
    Sweeper(
        parameter=Parameter.frequency,
        values=parameter_range,
        channels=[qubit.probe],
    )
]
platform.execute([sequence], [sweeper])
classmethod load(path: Path, instruments: Mapping[str, Instrument], qubits: Mapping[Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], Qubit], couplers: Mapping[Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], Qubit] | None = None, name: str | None = None) Platform[source]

Dump platform.

dump(path: Path)[source]

Dump platform.

qubit(qubit: Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])]) tuple[Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], Qubit][source]

Retrieve physical qubit name and object.

Temporary fix for the compiler to work for platforms where the qubits are not named as 0, 1, 2, …

coupler(coupler: Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])]) tuple[Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], Qubit][source]

Retrieve physical coupler name and object.

Temporary fix for the compiler to work for platforms where the couplers are not named as 0, 1, 2, …

class qibolab.BaseEnvelope[source]

Bases: ABC, Model

Pulse envelopes.

Generates both i (in-phase) and q (quadrature) components.

i(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]

In-phase envelope.

q(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]

Quadrature envelope.

envelopes(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]

Stacked i and q envelope waveforms of the pulse.

static normalize_trim_pulse(pulse: ndarray[tuple[Any, ...], dtype[float64]]) ndarray[tuple[Any, ...], dtype[float64]][source]

Normalize the pulse relative to its first sample, then remove the first and last samples.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.Rectangular(*, kind: Literal['rectangular'] = 'rectangular')[source]

Bases: BaseEnvelope

Rectangular envelope.

kind: Literal['rectangular']
i(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]

Generate a rectangular envelope.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.Exponential(*, kind: Literal['exponential'] = 'exponential', tau: float, upsilon: float, g: float = 0.1)[source]

Bases: BaseEnvelope

Exponential shape, i.e. square pulse with an exponential decay.

\[\frac{\exp\left(-\frac{x}{\text{upsilon}}\right) + g \exp\left(-\frac{x}{\text{tau}}\right)}{1 + g}\]
kind: Literal['exponential']
tau: float

The decay rate of the first exponential function.

In units of the interval duration.

upsilon: float

The decay rate of the second exponential function.

In units of the interval duration.

g: float

Weight of the second exponential function.

i(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]

Generate a combination of two exponential decays.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.Gaussian(*, kind: Literal['gaussian'] = 'gaussian', rel_sigma: float)[source]

Bases: BaseEnvelope

Gaussian pulse shape.

Parameters:

rel_sigma (float)

\[A\exp^{-\frac{1}{2}\frac{(t-\mu)^2}{\sigma^2}}\]
kind: Literal['gaussian']
rel_sigma: float

Relative Gaussian standard deviation.

In units of the interval duration.

i(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]

Generate a Gaussian window.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.GaussianSquare(*, kind: Literal['gaussian_square'] = 'gaussian_square', risefall: int = 0, sigma: float = 0)[source]

Bases: BaseEnvelope

Rectangular envelope with Gaussian rise and fall.

Note

The risefall and sigma are absolute values.

\[A\exp^{-\frac{1}{2}\frac{(t-\mu)^2}{\sigma^2}}[Rise] + Flat + A\exp^{-\frac{1}{2}\frac{(t-\mu)^2}{\sigma^2}}[Decay]\]
kind: Literal['gaussian_square']
risefall: int

Risefall time, in number of samples.

sigma: float

Gaussian standard deviation.

width(samples: int) float[source]
i(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]

Generate a Gaussian envelope, with a flat central window.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.Drag(*, kind: Literal['drag'] = 'drag', rel_sigma: float, beta: float)[source]

Bases: BaseEnvelope

Derivative Removal by Adiabatic Gate (DRAG) pulse envelope.

kind: Literal['drag']
rel_sigma: float

Relative Gaussian standard deviation.

In units of the interval duration.

beta: float

Beta.

i(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]

Generate a Gaussian envelope.

q(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]

Generate …

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.Iir(*, kind: Literal['iir'] = 'iir', a: Annotated[ndarray[tuple[Any, ...], dtype[_ScalarT]], PlainValidator(func=ndarray_deserialize, json_schema_input_type=Any), PlainSerializer(func=ndarray_serialize, return_type=str, when_used=always)], b: Annotated[ndarray[tuple[Any, ...], dtype[_ScalarT]], PlainValidator(func=ndarray_deserialize, json_schema_input_type=Any), PlainSerializer(func=ndarray_serialize, return_type=str, when_used=always)], target: BaseEnvelope)[source]

Bases: BaseEnvelope

IIR Filter using scipy.signal lfilter.

https://arxiv.org/pdf/1907.04818.pdf (page 11 - filter formula S22):

p = [A, tau_iir]
p = [b0 = 1−k +k ·α, b1 = −(1−k)·(1−α),a0 = 1 and a1 = −(1−α)]
p = [b0, b1, a0, a1]
kind: Literal['iir']
a: Annotated[ndarray[tuple[Any, ...], dtype[_ScalarT]], PlainValidator(func=ndarray_deserialize, json_schema_input_type=Any), PlainSerializer(func=ndarray_serialize, return_type=str, when_used=always)]
b: Annotated[ndarray[tuple[Any, ...], dtype[_ScalarT]], PlainValidator(func=ndarray_deserialize, json_schema_input_type=Any), PlainSerializer(func=ndarray_serialize, return_type=str, when_used=always)]
target: BaseEnvelope
i(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]
q(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]

Q. .. todo:

Add docstring
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.Snz(*, kind: Literal['snz'] = 'snz', t_idling: int, b_amplitude: float = 0.5)[source]

Bases: BaseEnvelope

Sudden variant Net Zero.

https://arxiv.org/abs/2008.07411 (Supplementary materials: FIG. S1.)

kind: Literal['snz']
t_idling: int

Absolute idling time, in number of samples.

b_amplitude: float

Relative B amplitude (wrt A).

i(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]
\[\begin{split}\\Phi(t) = \begin{cases} 1 & \text{for } 0 \\leq t < \tau \\ b & \text{for } t = \tau \\ 0 & \text{for } \tau < t < \tau + \tau_{idle}\\ b & \text{for } t = \tau + \tau_{idle}\\ -1 & \text{for } \tau + \tau_{idle} < t \\leq 2\tau + \tau_{idle} \\ \\end{cases}.\end{split}\]

Where $tau$ is the duration of the square pulse.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.ECap(*, kind: Literal['ecap'] = 'ecap', alpha: float)[source]

Bases: BaseEnvelope

ECap pulse envelope.

\[\begin{split}e_{\cap(t,\alpha)} &=& A[1 + \tanh(\alpha t/t_\theta)][1 + \tanh(\alpha (1 - t/t_\theta))]\\ &\times& [1 + \tanh(\alpha/2)]^{-2}\end{split}\]
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

kind: Literal['ecap']
alpha: float

In units of the inverse interval duration.

i(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]
class qibolab.Custom(*, kind: Literal['custom'] = 'custom', i_: Annotated[ndarray[tuple[Any, ...], dtype[_ScalarT]], PlainValidator(func=ndarray_deserialize, json_schema_input_type=Any), PlainSerializer(func=ndarray_serialize, return_type=str, when_used=always)], q_: Annotated[ndarray[tuple[Any, ...], dtype[_ScalarT]], PlainValidator(func=ndarray_deserialize, json_schema_input_type=Any), PlainSerializer(func=ndarray_serialize, return_type=str, when_used=always)])[source]

Bases: BaseEnvelope

Arbitrary envelope.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

kind: Literal['custom']
i_: Annotated[ndarray[tuple[Any, ...], dtype[_ScalarT]], PlainValidator(func=ndarray_deserialize, json_schema_input_type=Any), PlainSerializer(func=ndarray_serialize, return_type=str, when_used=always)]
q_: Annotated[ndarray[tuple[Any, ...], dtype[_ScalarT]], PlainValidator(func=ndarray_deserialize, json_schema_input_type=Any), PlainSerializer(func=ndarray_serialize, return_type=str, when_used=always)]
i(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]
q(samples: int) ndarray[tuple[Any, ...], dtype[float64]][source]
class qibolab.Acquisition(*, id_: ~uuid.Annotated[~uuid.UUID, ~pydantic.types.UuidVersion(uuid_version=4)] = <factory>, kind: ~typing.Literal['acquisition'] = 'acquisition', duration: float)[source]

Bases: _PulseLike

Acquisition instruction.

This event instructs the device to acquire samples for the event span.

Only valid on an acquisition channel.

kind: Literal['acquisition']
duration: float

Duration in ns.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.Align(*, id_: ~uuid.Annotated[~uuid.UUID, ~pydantic.types.UuidVersion(uuid_version=4)] = <factory>, kind: ~typing.Literal['align'] = 'align')[source]

Bases: _PulseLike

Brings different channels at the same point in time.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

kind: Literal['align']
class qibolab.Delay(*, id_: ~uuid.Annotated[~uuid.UUID, ~pydantic.types.UuidVersion(uuid_version=4)] = <factory>, kind: ~typing.Literal['delay'] = 'delay', duration: float)[source]

Bases: _PulseLike

Wait instruction.

During its length no pulse is sent on the same channel.

Valid on any channel.

kind: Literal['delay']
duration: float

Duration in ns.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.Pulse(*, id_: ~uuid.Annotated[~uuid.UUID, ~pydantic.types.UuidVersion(uuid_version=4)] = <factory>, kind: ~typing.Literal['pulse'] = 'pulse', duration: float, amplitude: float, envelope: ~qibolab._core.pulses.envelope.Rectangular | ~qibolab._core.pulses.envelope.Exponential | ~qibolab._core.pulses.envelope.Gaussian | ~qibolab._core.pulses.envelope.GaussianSquare | ~qibolab._core.pulses.envelope.Drag | ~qibolab._core.pulses.envelope.Iir | ~qibolab._core.pulses.envelope.Snz | ~qibolab._core.pulses.envelope.ECap | ~qibolab._core.pulses.envelope.Custom, relative_phase: float = 0.0)[source]

Bases: _PulseLike

A pulse to be sent to the QPU.

Valid on any channel, except acquisition ones.

kind: Literal['pulse']
duration: float

Pulse duration.

amplitude: float

Pulse digital amplitude (unitless).

Pulse amplitudes are normalised between -1 and 1.

envelope: Annotated[Rectangular | Exponential | Gaussian | GaussianSquare | Drag | Iir | Snz | ECap | Custom, FieldInfo(annotation=NoneType, required=True, discriminator='kind')]

The pulse envelope shape.

See qibolab.Envelope for list of available shapes.

relative_phase: float

Relative phase of the pulse, in radians.

i(sampling_rate: float) ndarray[tuple[Any, ...], dtype[float64]][source]

Compute the envelope of the waveform i component.

q(sampling_rate: float) ndarray[tuple[Any, ...], dtype[float64]][source]

Compute the envelope of the waveform q component.

envelopes(sampling_rate: float) ndarray[tuple[Any, ...], dtype[float64]][source]

Compute a tuple with the i and q envelopes.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.Readout(*, id_: ~uuid.Annotated[~uuid.UUID, ~pydantic.types.UuidVersion(uuid_version=4)] = <factory>, kind: ~typing.Literal['readout'] = 'readout', acquisition: ~qibolab._core.pulses.pulse.Acquisition, probe: ~qibolab._core.pulses.pulse.Pulse)[source]

Bases: _PulseLike

Readout instruction.

This event instructs the device to acquire samples for the event span.

Only valid on an acquisition channel.

kind: Literal['readout']
acquisition: Acquisition
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

probe: Pulse
classmethod from_probe(probe: Pulse)[source]

Create a whole readout operation from its probe pulse.

The acquisition is made to match the same probe duration.

property duration: float

Duration in ns.

property id: Annotated[UUID, UuidVersion(uuid_version=4)]

Instruction identifier.

new() Annotated[Align | Pulse | Delay | VirtualZ | Acquisition | Readout, FieldInfo(annotation=NoneType, required=True, discriminator='kind')][source]
class qibolab.VirtualZ(*, id_: ~uuid.Annotated[~uuid.UUID, ~pydantic.types.UuidVersion(uuid_version=4)] = <factory>, kind: ~typing.Literal['virtualz'] = 'virtualz', phase: float)[source]

Bases: _PulseLike

Implementation of Z-rotations using virtual phase.

Only valid on a drive channel.

kind: Literal['virtualz']
phase: float

Phase that implements the rotation.

property duration

Duration of the virtual gate should always be zero.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qibolab.Qubit(*, drive: ~typing.Annotated[str | None, True] = None, drive_extra: ~typing.Annotated[dict[~typing.Annotated[tuple[int, int], ~pydantic.functional_validators.BeforeValidator(func=~qibolab._core.identifier._split, json_schema_input_type=PydanticUndefined), ~pydantic.functional_serializers.PlainSerializer(func=~qibolab._core.identifier._join, return_type=PydanticUndefined, when_used=always)] | ~typing.Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], str], False] = <factory>, flux: ~typing.Annotated[str | None, True] = None, probe: ~typing.Annotated[str | None, True] = None, acquisition: ~typing.Annotated[str | None, True] = None)[source]

Bases: 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 qibolab.Platform

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': False}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

drive: Annotated[str | None, True]

Ouput channel, to drive the qubit state.

drive_extra: Annotated[dict[Annotated[tuple[int, int], BeforeValidator(func=_split, json_schema_input_type=PydanticUndefined), PlainSerializer(func=_join, return_type=PydanticUndefined, when_used=always)] | Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], str], False]

Output channels collection, to drive non-qubit transitions.

flux: Annotated[str | None, True]

Output channel, to control the qubit flux.

probe: Annotated[str | None, True]

Output channel, to probe the resonator.

acquisition: Annotated[str | None, True]

Input channel, to acquire the readout results.

property channels: list[str]
classmethod default(name: Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], channels: list[str] | None = None, **kwargs)[source]

Create a qubit with default channel names.

Default channel names follow the convention: ‘{qubit_name}/{channel_type}’

Parameters:
  • 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.

classmethod coupler(name: Annotated[int | str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], **kwargs)[source]

Create a qubit with default channel names.

class qibolab.PulseSequence(initlist=None)[source]

Bases: UserList[tuple[str, Annotated[Align | Pulse | Delay | VirtualZ | Acquisition | Readout, FieldInfo(annotation=NoneType, required=True, discriminator=’kind’)]]]

Synchronized sequence of control instructions across multiple channels.

The sequence is a linear stream of instructions, which may be executed in parallel over multiple channels.

Each instruction is composed by the pulse-like object representing the action, and the channel on which it should be performed.

classmethod load(value: list[tuple[str, Annotated[Align | Pulse | Delay | VirtualZ | Acquisition | Readout, FieldInfo(annotation=NoneType, required=True, discriminator='kind')]]])[source]
property duration: float

Duration of the entire sequence.

property channels: set[str]

Channels involved in the sequence.

channel(channel: str) Iterable[Annotated[Align | Pulse | Delay | VirtualZ | Acquisition | Readout, FieldInfo(annotation=NoneType, required=True, discriminator='kind')]][source]

Isolate pulses on a given channel.

channel_duration(channel: str) float[source]

Duration of the given channel.

pulse_channels(pulse_id: Annotated[UUID, UuidVersion(uuid_version=4)]) list[str][source]

Find channels on which a pulse with a given id plays.

concatenate(other: Iterable[tuple[str, Annotated[Align | Pulse | Delay | VirtualZ | Acquisition | Readout, FieldInfo(annotation=NoneType, required=True, discriminator='kind')]]]) None[source]

Concatenate two sequences.

Appends other in-place such that the result is:

  • self

  • necessary delays to synchronize channels

  • other

Guarantees that the all the channels in the concatenated sequence will start simultaneously

juxtapose(other: Iterable[tuple[str, Annotated[Align | Pulse | Delay | VirtualZ | Acquisition | Readout, FieldInfo(annotation=NoneType, required=True, discriminator='kind')]]]) None[source]

Juxtapose two sequences.

Appends other in-place such that the result is:

  • self

  • necessary delays to synchronize channels

  • other

Guarantee simultaneous start and no overlap.

align(channels: list[str]) Align[source]

Introduce align commands to the sequence.

align_to_delays() PulseSequence[source]

Compile align commands to delays.

trim() PulseSequence[source]

Drop final delays.

The operation is not in place, and does not modify the original sequence.

property acquisitions: list[tuple[str, Readout | Acquisition]]

Return list of the readout pulses in this sequence.

Note

This selects only the Acquisition events, and not all the instructions directed to an acquistion channel

property split_readouts: PulseSequence

Split readout operations in its constituents.

This will also double the rest of the channels (mainly delays) on which the readouts are placed, assuming the probe channels to be absent.

Note

Since Readout is only placed on an acquisition channel, the name of the associated probe channel is actually unknown. This function assumes the convention that the relevant channels are named .../acquisition and .../probe.

property by_channel: dict[str, list[Annotated[Align | Pulse | Delay | VirtualZ | Acquisition | Readout, FieldInfo(annotation=NoneType, required=True, discriminator='kind')]]]

Separate sequence into channels dictionary.

class qibolab.Parameter(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]

Bases: Enum

Sweeping parameters.

frequency = (1, 'channel')
amplitude = (2, 'pulse')
duration = (3, 'pulse')
duration_interpolated = (4, 'pulse')
relative_phase = (5, 'pulse')
phase = (6, 'pulse')
offset = (7, 'channel')
classmethod channels() set[Parameter][source]

Set of parameters to be swept on the channel.

class qibolab.Sweeper(*, parameter: Parameter, values: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None = None, range: tuple[float, float, float] | None = None, pulses: list[Annotated[Align | Pulse | Delay | VirtualZ | Acquisition | Readout, FieldInfo(annotation=NoneType, required=True, discriminator='kind')]] | None = None, channels: list[str] | None = None)[source]

Bases: Model

Data structure for Sweeper object.

This object is passed as an argument to the method qibolab.Platform.execute() which enables the user to sweep a specific parameter for one or more pulses. For information on how to perform sweeps see qibolab.Platform.execute().

Example

import numpy as np
from qibolab import Parameter, PulseSequence, Sweeper, create_dummy


platform = create_dummy()
qubit = platform.qubits[0]
natives = platform.natives.single_qubit[0]
sequence = natives.MZ.create_sequence()
parameter_range = np.random.randint(10, size=10)
sweeper = Sweeper(
    parameter=Parameter.frequency, values=parameter_range, channels=[qubit.probe]
)
platform.execute([sequence], [[sweeper]])
parameter: Parameter

Parameter to be swept.

values: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None

Array of parameter values to sweep over.

range: tuple[float, float, float] | None

Tuple of (start, stop, step).

To sweep over the array np.arange(start, stop, step). Can be provided instead of values for more efficient sweeps on some instruments.

pulses: list[Annotated[Align | Pulse | Delay | VirtualZ | Acquisition | Readout, FieldInfo(annotation=NoneType, required=True, discriminator='kind')]] | None

List of qibolab.Pulse to be swept.

channels: list[str] | None

List of channel names for which the parameter should be swept.

check_values()[source]
property irange: tuple[float, float, float]

Inferred range.

Always ensure a range, inferring it from values if range is not set.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

Subpackages