qblox_backend#

Compiler backend for Qblox hardware.

Module Contents#

Classes#

LongPulseReplacementSpec

Specification for replacing long waveform pulses using a factory function.

OperationTimingInfo

Timing information for an Operation.

ConditionalInfo

Container for conditional address data.

QbloxHardwareCompilationConfig

Data structure containing the information needed to compile to the Qblox backend.

_LocalOscillatorCompilationConfig

Configuration values for a

AllowedChannels

Allowed channels for a specific sequencer.

_ClusterModuleCompilationConfig

Configuration values for a ClusterModuleCompiler.

_QCMCompilationConfig

QCM-specific configuration values for a ClusterModuleCompiler.

_QRMCompilationConfig

QRM-specific configuration values for a ClusterModuleCompiler.

_QCMRFCompilationConfig

QCM_RF-specific configuration values for a ClusterModuleCompiler.

_QRMRFCompilationConfig

QRMRF-specific configuration values for a ClusterModuleCompiler.

_QRCCompilationConfig

QRC-specific configuration values for a ClusterModuleCompiler.

_QTMCompilationConfig

QTM-specific configuration values for a ClusterModuleCompiler.

_SequencerCompilationConfig

Configuration values for a SequencerCompiler.

_ClusterCompilationConfig

Configuration values for a ClusterCompiler.

ChannelPath

Path of a sequencer channel.

Functions#

_replace_long_pulses_recursively(...)

Recursively replace long waveform pulses defined by multiple specs.

compile_long_pulses_to_awg_offsets(...)

Replace square and ramp pulses in the schedule with stitched long pulses using AWG offsets.

_all_conditional_acqs_and_control_flows_and_latch_reset(→ None)

_get_module_type(→ qblox_instruments.InstrumentType)

_update_conditional_info_from_acquisition(→ None)

_set_conditional_info_map(→ None)

_insert_latch_reset(→ None)

compile_conditional_playback(...)

Compiles conditional playback.

hardware_compile(...)

Generate qblox hardware instructions for executing the schedule.

_add_support_input_channel_names(→ None)

_all_abs_times_ops_with_voltage_offsets_pulses(→ None)

_add_clock_freqs_to_set_clock_frequency(→ None)

validate_non_overlapping_stitched_pulse(→ None)

Raise an error when pulses overlap, if at least one contains a voltage offset.

_exists_pulse_starting_before_current_end(...)

_raise_if_pulses_overlap_on_same_port_clock(→ None)

Raise an error if any pulse operations overlap on the same port-clock.

_get_pulse_start_ends(→ dict[str, tuple[float, float]])

_operation_end(→ float)

Attributes#

SequencerIndex

Index of a sequencer.

exception QbloxModuleNotFoundError[source]#

Bases: KeyError

Exception raised when a module is not defined in the hardware description.

class LongPulseReplacementSpec[source]#

Specification for replacing long waveform pulses using a factory function.

This dataclass encapsulates the criteria and behavior for identifying and replacing specific waveform types (e.g., square, ramp) based on their waveform function name and minimum duration.

wf_func_name: str[source]#

The name of the waveform function to match, e.g., quantify_scheduler.waveforms.square.

min_duration: float[source]#

The minimum duration (in seconds) a pulse must have to be eligible for replacement.

pulse_factory: Callable[source]#

A function that generates the replacement pulse, e.g., long_square_pulse.

extra_kwargs: Callable[[dict], dict][source]#

A callable that receives the original pulse_info dictionary and returns additional keyword arguments to be passed to the pulse_factory.

match(pulse_info: dict) bool[source]#

Checks whether the pulse_info matches with the current spec.

_replace_long_pulses_recursively(operation: quantify_scheduler.operations.operation.Operation | quantify_scheduler.schedules.schedule.Schedule, specs: list[LongPulseReplacementSpec]) quantify_scheduler.operations.operation.Operation | None[source]#

Recursively replace long waveform pulses defined by multiple specs.

Parameters:
  • operation – An operation or schedule possibly containing long pulses.

  • specs – A list of LongPulseReplacementSpec, each describing one waveform type to replace.

Returns:

Operation | None Replacing operation if applicable. None if no replacement was required.

compile_long_pulses_to_awg_offsets(schedule: quantify_scheduler.schedules.schedule.Schedule, config: quantify_scheduler.structure.model.DataStructure | dict) quantify_scheduler.schedules.schedule.Schedule[source]#

Replace square and ramp pulses in the schedule with stitched long pulses using AWG offsets.

Parameters:

schedule (Schedule) – A schedule possibly containing long square or ramp pulses.

Returns:

schedule : Schedule Modified schedule with long pulses replaced using AWG offsets.

_all_conditional_acqs_and_control_flows_and_latch_reset(operation: quantify_scheduler.operations.operation.Operation | quantify_scheduler.schedules.schedule.Schedule, time_offset: float, accumulator: list[tuple[float, quantify_scheduler.operations.operation.Operation]]) None[source]#
class OperationTimingInfo[source]#

Timing information for an Operation.

start: float[source]#

start time of the operation.

end: float[source]#

end time of the operation.

classmethod from_operation_and_schedulable(operation: quantify_scheduler.operations.operation.Operation, schedulable: quantify_scheduler.schedules.schedule.Schedulable) OperationTimingInfo[source]#

Create an OperationTimingInfo from an operation and a schedulable.

overlaps_with(operation_timing_info: OperationTimingInfo) bool[source]#

Check if this operation timing info overlaps with another.

class ConditionalInfo[source]#

Container for conditional address data.

portclocks: set[tuple[str, str]][source]#

Port-clocks reading from the trigger address.

address: int[source]#

Trigger address.

_trigger_invert: bool | None = None[source]#
_trigger_count: int | None = None[source]#
property trigger_invert: bool | None[source]#

If True, inverts the threshold comparison result when reading from the trigger address counter.

If a ThresholdedTriggerCount acquisition is done with a QRM, this must be set according to the condition you are trying to measure (greater than /equal to the threshold, or less than the threshold). If it is done with a QTM, this is set to False.

property trigger_count: int | None[source]#

The sequencer trigger address counter threshold.

If a ThresholdedTriggerCount acquisition is done with a QRM, this must be set to the counts threshold. If it is done with a QTM, this is set to 1.

_get_module_type(port: str, clock: str, compilation_config: quantify_scheduler.backends.graph_compilation.CompilationConfig) qblox_instruments.InstrumentType[source]#
_update_conditional_info_from_acquisition(acq_info: dict[str, Any], cond_info: collections.defaultdict[str, ConditionalInfo], compilation_config: quantify_scheduler.backends.graph_compilation.CompilationConfig) None[source]#
_set_conditional_info_map(operation: quantify_scheduler.operations.operation.Operation | quantify_scheduler.schedules.schedule.Schedule, conditional_info_map: collections.defaultdict[str, ConditionalInfo], compilation_config: quantify_scheduler.backends.graph_compilation.CompilationConfig) None[source]#
_insert_latch_reset(operation: quantify_scheduler.operations.operation.Operation | quantify_scheduler.schedules.schedule.Schedule, abs_time_relative_to_schedule: float, schedule: quantify_scheduler.schedules.schedule.Schedule, conditional_info_map: collections.defaultdict[str, ConditionalInfo]) None[source]#
compile_conditional_playback(schedule: quantify_scheduler.schedules.schedule.Schedule, config: quantify_scheduler.backends.graph_compilation.CompilationConfig) quantify_scheduler.schedules.schedule.Schedule[source]#

Compiles conditional playback.

This compiler pass will determine the mapping between trigger labels and trigger addresses that the hardware will use. The feedback trigger address is stored under the key feedback_trigger_address in pulse_info and in acquisition_info of the corresponding operation.

A valid conditional playback consists of two parts: (1) a conditional acquisition or measure, and (2) a conditional control flow. The first should always be followed by the second, else an error is raised. A conditional acquisition sends a trigger after the acquisition ends and if the acquisition crosses a certain threshold. Each sequencer that is subscribed to this trigger will increase their latch counters by one. To ensure the latch counters contain either 0 or 1 trigger counts, a LatchReset operation is inserted right after the start of a conditional acquisition, on all sequencers. If this is not possible (e.g. due to concurring operations), a RuntimeError is raised.

Parameters:

schedule – The schedule to compile.

Returns:

Schedule The returned schedule is a reference to the original schedule, but updated.

Raises:

RuntimeError

  • If a conditional acquisitions/measures is not followed by a conditional control flow.

  • If a conditional control flow is not preceded by a conditional acquisition/measure.

  • If the compilation pass is unable to insert LatchReset on all sequencers.

hardware_compile(schedule: quantify_scheduler.schedules.schedule.Schedule, config: quantify_scheduler.backends.graph_compilation.CompilationConfig) quantify_scheduler.schedules.schedule.CompiledSchedule[source]#

Generate qblox hardware instructions for executing the schedule.

The principle behind the overall compilation is as follows:

For every instrument in the hardware configuration, we instantiate a compiler object. Then we assign all the pulses/acquisitions that need to be played by that instrument to the compiler, which then compiles for each instrument individually.

This function then returns all the compiled programs bundled together in a dictionary with the QCoDeS name of the instrument as key.

Parameters:
  • schedule – The schedule to compile. It is assumed the pulse and acquisition info is already added to the operation. Otherwise an exception is raised.

  • config – Compilation config for QuantifyCompiler.

Returns:

: The compiled schedule.

class QbloxHardwareCompilationConfig(/, **data: Any)[source]#

Bases: quantify_scheduler.backends.types.common.HardwareCompilationConfig

Data structure containing the information needed to compile to the Qblox backend.

This information is structured in the same way as in the generic HardwareCompilationConfig, but contains fields for hardware-specific settings.

config_type: type[QbloxHardwareCompilationConfig] = None[source]#

A reference to the HardwareCompilationConfig DataStructure for the Qblox backend.

version: str = None[source]#

Version of the specific hardware compilation config used.

hardware_description: dict[str, quantify_scheduler.backends.types.qblox.QbloxHardwareDescription | quantify_scheduler.backends.types.common.HardwareDescription][source]#

Description of the instruments in the physical setup.

hardware_options: quantify_scheduler.backends.types.qblox.QbloxHardwareOptions[source]#

Options that are used in compiling the instructions for the hardware, such as LatencyCorrection or SequencerOptions.

allow_off_grid_nco_ops: bool | None = None[source]#

Flag to allow NCO operations to play at times that are not aligned with the NCO grid.

compilation_passes: list[quantify_scheduler.backends.graph_compilation.SimpleNodeConfig][source]#

The list of compilation nodes that should be called in succession to compile a schedule to instructions for the Qblox hardware.

_validate_connectivity_channel_names() QbloxHardwareCompilationConfig[source]#
_warn_mix_lo_false() QbloxHardwareCompilationConfig[source]#
classmethod from_old_style_hardware_config(data: Any) Any[source]#

Convert old style hardware config dict to new style before validation.

classmethod _validate_versioning(config: dict[str, Any]) dict[str, Any][source]#
_extract_instrument_compilation_configs(portclocks_used: set[tuple]) dict[str, Any][source]#

Extract an instrument compiler config for each instrument mentioned in hardware_description. Each instrument config has a similar structure as QbloxHardwareCompilationConfig , but contains only the settings related to their related instrument. Each config must contain at least one ortclock referenced in portclocks_used, otherwise the config is deleted.

_get_all_portclock_to_path_and_lo_name_to_path(portclocks_used: set[tuple[str, str]], cluster_configs: dict[str, _ClusterCompilationConfig], lo_configs: dict[str, _LocalOscillatorCompilationConfig]) None[source]#
class _LocalOscillatorCompilationConfig(/, **data: Any)[source]#

Bases: quantify_scheduler.structure.model.DataStructure

Configuration values for a quantify_scheduler.backends.qblox.instrument_compilers.LocalOscillatorCompiler.

hardware_description: quantify_scheduler.backends.types.common.LocalOscillatorDescription[source]#

Description of the physical setup of this local oscillator.

frequency: float | None = None[source]#

The frequency of this local oscillator.

SequencerIndex[source]#

Index of a sequencer.

class AllowedChannels(/, **data: Any)[source]#

Bases: quantify_scheduler.structure.model.DataStructure

Allowed channels for a specific sequencer.

output: set[str][source]#

Allowed outputs.

For example {“complex_output_0”, “real_output_0”, `digital_output_0”}.

input: set[str][source]#

Allowed inputs.

For example {“complex_input_1”, “real_input_1”}.

class _ClusterModuleCompilationConfig(/, **data: Any)[source]#

Bases: abc.ABC, quantify_scheduler.structure.model.DataStructure

Configuration values for a ClusterModuleCompiler.

hardware_description: quantify_scheduler.backends.types.qblox.ClusterModuleDescription[source]#

Description of the physical setup of this module.

hardware_options: quantify_scheduler.backends.types.qblox.QbloxHardwareOptions[source]#

Options that are used in compiling the instructions for the hardware.

portclock_to_path: dict[str, ChannelPath][source]#

Mapping between portclocks and their associated channel name paths (e.g. cluster0.module1.complex_output_0).

lo_to_path: dict[str, ChannelPath][source]#

Mapping between lo names and their associated channel name paths (e.g. cluster0.module1.complex_output_0).

parent_config_version: str[source]#

Version of the parent hardware compilation config used.

sequencer_allowed_channels: dict[SequencerIndex, AllowedChannels][source]#

Allowed channels for each sequencer.

_sequencer_to_portclock() dict[SequencerIndex, str][source]#
_extract_sequencer_compilation_configs() dict[int, _SequencerCompilationConfig][source]#
_validate_hardware_distortion_corrections_mode() _ClusterModuleCompilationConfig[source]#
_validate_input_gain_mode() _ClusterModuleCompilationConfig[source]#
_validate_channel_name_measure() None[source]#
class _QCMCompilationConfig(/, **data: Any)[source]#

Bases: _ClusterModuleCompilationConfig

QCM-specific configuration values for a ClusterModuleCompiler.

sequencer_allowed_channels: dict[SequencerIndex, AllowedChannels][source]#

Allowed channels for each sequencer.

_validate_channel_name_measure() None[source]#
class _QRMCompilationConfig(/, **data: Any)[source]#

Bases: _ClusterModuleCompilationConfig

QRM-specific configuration values for a ClusterModuleCompiler.

sequencer_allowed_channels: dict[SequencerIndex, AllowedChannels][source]#

Allowed channels for each sequencer.

_validate_channel_name_measure() None[source]#
class _QCMRFCompilationConfig(/, **data: Any)[source]#

Bases: _ClusterModuleCompilationConfig

QCM_RF-specific configuration values for a ClusterModuleCompiler.

sequencer_allowed_channels: dict[SequencerIndex, AllowedChannels][source]#

Allowed channels for each sequencer.

_validate_channel_name_measure() None[source]#
class _QRMRFCompilationConfig(/, **data: Any)[source]#

Bases: _ClusterModuleCompilationConfig

QRMRF-specific configuration values for a ClusterModuleCompiler.

sequencer_allowed_channels: dict[SequencerIndex, AllowedChannels][source]#

Allowed channels for each sequencer.

_validate_channel_name_measure() None[source]#
class _QRCCompilationConfig(/, **data: Any)[source]#

Bases: _ClusterModuleCompilationConfig

QRC-specific configuration values for a ClusterModuleCompiler.

sequencer_allowed_channels: dict[SequencerIndex, AllowedChannels][source]#

Allowed channels for each sequencer.

class _QTMCompilationConfig(/, **data: Any)[source]#

Bases: _ClusterModuleCompilationConfig

QTM-specific configuration values for a ClusterModuleCompiler.

sequencer_allowed_channels: dict[SequencerIndex, AllowedChannels][source]#

Allowed channels for each sequencer.

_validate_channel_name_measure() None[source]#
class _SequencerCompilationConfig(/, **data: Any)[source]#

Bases: quantify_scheduler.structure.model.DataStructure

Configuration values for a SequencerCompiler.

hardware_description: quantify_scheduler.backends.types.qblox.ComplexChannelDescription | quantify_scheduler.backends.types.qblox.RealChannelDescription | quantify_scheduler.backends.types.qblox.DigitalChannelDescription[source]#

Information needed to specify a complex/real/digital input/output.

sequencer_options: quantify_scheduler.backends.types.qblox.SequencerOptions[source]#

Configuration options for this sequencer.

portclock: str[source]#

Portclock associated to this sequencer.

channel_name: str[source]#

Channel name associated to this sequencer.

channel_name_measure: None | list[str][source]#

Extra channel name necessary to define a Measure operation.

latency_correction: quantify_scheduler.backends.types.common.LatencyCorrection[source]#

Latency correction that should be applied to operations on this sequencer.

distortion_correction: quantify_scheduler.backends.types.common.SoftwareDistortionCorrection | None[source]#

Distortion corrections that should be applied to waveforms on this sequencer.

lo_name: str | None[source]#

Local oscillator associated to this sequencer.

modulation_frequencies: quantify_scheduler.backends.types.common.ModulationFrequencies[source]#

Modulation frequencies associated to this sequencer.

mixer_corrections: quantify_scheduler.backends.types.qblox.QbloxMixerCorrections | None[source]#

Mixer correction settings.

digitization_thresholds: quantify_scheduler.backends.types.qblox.DigitizationThresholds | None = None[source]#

The settings that determine when an analog voltage is counted as a pulse.

class _ClusterCompilationConfig(/, **data: Any)[source]#

Bases: quantify_scheduler.structure.model.DataStructure

Configuration values for a ClusterCompiler.

hardware_description: quantify_scheduler.backends.types.qblox.ClusterDescription[source]#

Description of the physical setup of this cluster.

hardware_options: quantify_scheduler.backends.types.qblox.QbloxHardwareOptions[source]#

Options that are used in compiling the instructions for the hardware.

portclock_to_path: dict[str, ChannelPath][source]#

Mapping between portclocks and their associated channel name paths (e.g. cluster0.module1.complex_output_0).

lo_to_path: dict[str, ChannelPath][source]#

Mapping between lo names and their associated channel name paths (e.g. cluster0.module1.complex_output_0).

parent_config_version: str[source]#

Version of the parent hardware compilation config used.

module_config_classes: dict[source]#
_extract_module_compilation_configs() dict[int, _ClusterModuleCompilationConfig][source]#
_add_support_input_channel_names(module_config: _ClusterModuleCompilationConfig) None[source]#
class ChannelPath[source]#

Path of a sequencer channel.

cluster_name: str[source]#
module_name: str[source]#
channel_name: str[source]#
module_idx: int[source]#
channel_name_measure: None | set[str] = None[source]#
classmethod from_path(path: str) ChannelPath[source]#

Instantiate a ChannelPath object from a path string.

property channel_idx: int[source]#

The channel index in the channel name.

A channel name is always formatted as “type_direction_#” where # is the channel index. This property extracts the channel index.

add_channel_name_measure(channel_name_measure: str) None[source]#

Add an extra input channel name for measure operation.

_all_abs_times_ops_with_voltage_offsets_pulses(operation: quantify_scheduler.operations.operation.Operation | quantify_scheduler.schedules.schedule.Schedule, time_offset: float, accumulator: list[tuple[float, quantify_scheduler.operations.operation.Operation]]) None[source]#
_add_clock_freqs_to_set_clock_frequency(schedule: quantify_scheduler.schedules.schedule.Schedule, operation: quantify_scheduler.operations.operation.Operation | quantify_scheduler.schedules.schedule.Schedule | None = None) None[source]#
validate_non_overlapping_stitched_pulse(schedule: quantify_scheduler.schedules.schedule.Schedule) None[source]#

Raise an error when pulses overlap, if at least one contains a voltage offset.

Since voltage offsets are sometimes used to construct pulses (see e.g. long_square_pulse()), overlapping these with regular pulses in time on the same port-clock can lead to undefined behaviour.

Note that for each schedulable, all pulse info entries with the same port and clock count as one pulse for that port and clock. This is because schedulables, starting before another schedulable has finished, could affect the waveforms or offsets in the remaining time of that other schedulable.

Parameters:

schedule (Schedule) – A Schedule, possibly containing long square pulses.

Returns:

schedule : Schedule A Schedule, possibly containing long square pulses.

Raises:

RuntimeError – If the schedule contains overlapping pulses (containing voltage offsets) on the same port and clock.

_exists_pulse_starting_before_current_end(abs_times_and_operations: list[tuple[float, quantify_scheduler.operations.operation.Operation]], current_idx: int) tuple[float, quantify_scheduler.operations.operation.Operation] | Literal[False][source]#
_raise_if_pulses_overlap_on_same_port_clock(abs_time_a: float, op_a: quantify_scheduler.operations.operation.Operation, abs_time_b: float, op_b: quantify_scheduler.operations.operation.Operation) None[source]#

Raise an error if any pulse operations overlap on the same port-clock.

A pulse here means a waveform or a voltage offset.

_get_pulse_start_ends(abs_time: float, operation: quantify_scheduler.operations.operation.Operation) dict[str, tuple[float, float]][source]#
_operation_end(abs_time_and_operation: tuple[float, quantify_scheduler.operations.operation.Operation]) float[source]#