qat.ir.instruction_builder module

Instruction builder abstractions and a concrete quantum builder.

This module defines the abstract InstructionBuilder API and a concrete QuantumInstructionBuilder which implements pulse-level gate construction and measurement helpers. The builders produce an IR InstructionBlock suitable for later compilation and scheduling stages.

class InstructionBuilder(hardware_model, instructions=None, _qubit_index_by_uuid=None, _qubits_ordered_by_index=None)

Bases: ABC

Abstract class for assembling quantum programs.

Provides a number of methods to deal with common quantum semantics, such as qubits, gates, measurements, and control flow. The details of how quantum operations are implemented are left to child classes.

abstract ECR(control, target)
Return type:

InstructionBuilder

S(target)
Return type:

InstructionBuilder

SX(target)
Return type:

InstructionBuilder

SXdg(target)
Return type:

InstructionBuilder

Sdg(target)
Return type:

InstructionBuilder

T(target)
Return type:

InstructionBuilder

Tdg(target)
Return type:

InstructionBuilder

abstract U(target, theta, phi, lamb, pulse_channel=None)
Return type:

InstructionBuilder

abstract X(target, theta=3.141592653589793, pulse_channel=None)
Return type:

InstructionBuilder

abstract Y(target, theta=3.141592653589793, pulse_channel=None)
Return type:

InstructionBuilder

abstract Z(target, theta=3.141592653589793, pulse_channel=None)
Return type:

InstructionBuilder

add(*instructions, flatten=False)

Add one or more instruction(s) into this builder.

All methods should use this instead of accessing the instructions tree directly as it deals with composite instructions.

Return type:

InstructionBuilder

assign(name, value)
Return type:

InstructionBuilder

cX(controllers, target, theta=3.141592653589793)
Return type:

InstructionBuilder

cY(controllers, target, theta=3.141592653589793)
Return type:

InstructionBuilder

cZ(controllers, target, theta=3.141592653589793)
Return type:

InstructionBuilder

abstract ccnot(controllers, target)
Return type:

InstructionBuilder

cnot(control, target)
Return type:

InstructionBuilder

static constrain(angle)

Constrain the rotation angle to avoid redundant rotations around the Bloch sphere.

abstract controlled(controllers, builder)
Return type:

InstructionBuilder

cswap(controllers, target, destination)
Return type:

InstructionBuilder

flatten()

Flatten the instruction builder by removing nested structures like InstructionBlocks.

get_logical_qubit(index)

Returns the qubit assigned with the given logical index.

Parameters:

index (int) – The logical index of the qubit to return.

Return type:

Qubit

Returns:

The qubit with the given logical index.

get_physical_qubit(index)

Returns the qubit assigned with the given physical index.

Parameters:

index (int) – The index of the qubit to return.

Return type:

Qubit

Returns:

The qubit with the given index.

had(target)
Return type:

InstructionBuilder

property instructions
jump(label, condition=None)
Return type:

InstructionBuilder

abstract measure_with_granular_post_processing(target, axis=SEQUENCE, output_variable=None)

Measure a qubit and emit the full granular post-processing pipeline.

Compiler frontends should call this method when lowering a measurement assignment into IR. The granular discrimination chain is emitted for both qubits with post_process_method configured and legacy qubits. For configured qubits, the chain (for example EqualiseDiscriminate) is derived from the configured post-processing method; for legacy qubits, the equivalent granular chain is derived from legacy mean_z_map_args data.

See QuantumInstructionBuilder.measure_with_granular_post_processing() for full detail.

property number_of_instructions
property qubits: list[Qubit]

Returns the list of qubits, sorted by index.

repeat(repeat_count)
Return type:

InstructionBuilder

abstract reset(targets, **kwargs)
Return type:

QuantumInstructionBuilder

results_processing(variable, res_format)
Return type:

InstructionBuilder

returns(variables=None)

Add return statement.

Return type:

InstructionBuilder

abstract swap(target, destination)
Return type:

InstructionBuilder

PydQuantumInstructionBuilder

alias of QuantumInstructionBuilder

class QuantumInstructionBuilder(*args, **kwargs)

Bases: InstructionBuilder

A pulse-level instruction builder, that provides implementations of quantum gates, and an API for pulse-level instructions.

ECR(control, target)
Return type:

QuantumInstructionBuilder

U(target, theta, phi, lamb, pulse_channel=None)

Adds an arbitrary rotation around the Bloch sphere with 3 Euler angles to the builder (see https://doi.org/10.48550/arXiv.1707.03429).

Parameters:
  • target (Qubit) – The qubit to be rotated.

  • theta (float) – Rotation angle.

  • phi (float) – Rotation angle.

  • lamb (float) – Rotation angle.

  • pulse_channel (Optional[PulseChannel]) – The pulse channel the pulses get sent to.

X(target, theta=3.141592653589793, *args, **kwargs)
Y(target, theta=3.141592653589793, *args, **kwargs)
Z(target, theta=3.141592653589793, *args, **kwargs)
ZX(target1, target2, theta=0.7853981633974483)

Adds a two-qubit interaction gate exp(-i heta Z x X) to the builder.

Parameters:
  • target1 (Qubit) – The qubit to which Z gets applied to.

  • target2 (Qubit) – The qubit to which X gets applied to.

  • theta (float) – The applied rotation angle.

acquire(target, delay=1e-06, output_variable=None, **kwargs)
Return type:

QuantumInstructionBuilder

static build_equalise_discriminate_instrs(qubit, output_variable)

Build the Equalise Discriminate instruction pair for any qubit type.

This is the single authoritative implementation of the three-way dispatch used by both emit_granular_post_processing() and InsertPreSelectionMeasurement. Both pre-selection and circuit-measurement paths produce identical pairs for the same qubit, differing only in the PostSelect.additional_disallowed that follows.

Dispatch:

Parameters:
  • qubit (Qubit) – Qubit whose post-processing configuration drives dispatch.

  • output_variable (str) – Variable name to attach to each instruction.

Return type:

list[Equalise | Discriminate]

Returns:

List of [Equalise, Discriminate] (or [Discriminate] for ML without a pre-rotation).

static build_legacy_equalise_args(mean_z_map_args)

Compute Equalise parameters and discrimination threshold from mean_z_map_args.

Given mean_z_map_args = [A, B] where the legacy linear map is z = Re(A * iq + B), the affine transform applied to the IQ vector [I, Q] is:

[I', Q'] = [[a, -b], [b, a]] @ [I, Q] + [c_I, c_Q]

where a + jb = A and c_I + jc_Q = B. This is identical to the transform used by the LinearMapToRealMethod branch of emit_granular_post_processing().

The discrimination threshold is 0.0 — the midpoint on the real axis between the rotated state centroids — matching the convention of Discriminate (> 0 "0", 0 "1").

Parameters:

mean_z_map_args (list) – Two-element list [A, B] as stored on the legacy qubit.

Return type:

tuple[ndarray, ndarray, float]

Returns:

(transform, offset, threshold) tuple.

ccnot(controllers, target)
Return type:

QuantumInstructionBuilder

cnot(control, target)
Return type:

QuantumInstructionBuilder

controlled(controllers, builder)
Return type:

QuantumInstructionBuilder

create_pulse_channel(frequency, physical_channel, imbalance=1.0, phase_iq_offset=0.0, scale=1 + 0j, uuid=None)

Creates a pulse channel and adds stores it within the builder.

The channel can be provided as a physical channel which the logical channel is linked too, or use the physical channel of a provided pulse channel.

Return type:

PulseChannel

delay(target, duration)
Return type:

QuantumInstructionBuilder

emit_granular_post_processing(target, output_variable)

Emit the granular post-processing instruction chain (without PostSelect).

Emits EqualiseDiscriminate based on the qubit’s configuration. Discriminate outputs integer state keys directly. Use emit_post_select() separately to append a PostSelect when disallowed states are configured.

Dispatches as follows:

  • LinearMapToRealMethodEqualise + Discriminate (threshold path; above-threshold → key 0, below → key 1).

  • MaxLikelihoodMethod → optional Equalise + Discriminate (ML path; emits dict keys directly).

  • Legacy (post_process_method is None, mean_z_map_args set) → Equalise (rotation derived from mean_z_map_args) + Discriminate.

Integer key convention

Discriminate emits the integer dict key from states for ML paths, or 0/1 for threshold/legacy paths. Non-negative keys are allowed states written to the classical register; negative keys are disallowed and subsequently filtered by PostSelect.

Results Format Semantics with Compiler Config

Integer output values from Discriminate flow through the runtime pipeline where results_format flags determine final encoding:

  • ``raw()``: Complex IQ arrays from EqualiseResult (post-mask applied). For legacy acquires without an Equalise step, falls back to the mapped arrays.

  • ``binary()``: Per-shot int output-value array from Discriminate (one value per retained shot, e.g. [0, 1, 0, ...]). With post-selection, only retained shots are included.

  • ``binary_count()``: Dictionary of state string → count using label_count() on the integer keys from DiscriminateResult. Key difference: when post-selection is active, the repeat count passed to binary_count() is shots_retained (not shots_requested), so counts reflect only the passing shots.

Example: 3-state ML with state keyed as -2 (disallowed)

Setup:

states = {
    0: MLDiscriminateParams(location=1+0j),
    1: MLDiscriminateParams(location=-1+0j),
    -2: MLDiscriminateParams(location=0+1j),  # negative key = disallowed
}
# 10 shots: 4 → key 0, 3 → key 1, 3 → key -2 (filtered by post-select)

After Discriminate:

[0, 0, 0, 0, 1, 1, 1, -2, -2, -2]

After PostSelect + global mask (7 retained):

[0, 0, 0, 0, 1, 1, 1]

Format outcomes:

raw():          <complex IQ from EqualiseResult, 7 retained shots>
binary():       [0, 0, 0, 0, 1, 1, 1]
binary_count(): {"0": 4, "1": 3}  (from 7 retained, not 10 requested)

Default Behavior

When CompilerConfig.results_format is not set, it defaults to ResultsFormatting.DynamicStructureReturn, which simplifies output (removes generated variable names, unwraps single-value results).

Parameters:
  • target (Qubit) – Qubit whose configuration drives the emitted instructions.

  • output_variable (str) – The variable name to attach to the instructions.

Return type:

QuantumInstructionBuilder

Returns:

The builder instance.

emit_post_select(output_variable)

Emit a PostSelect instruction after the Discriminate for the given variable.

PostSelect filters shots whose integer state key is negative. When all keys are non-negative (e.g. LinearMapToRealMethod always produces 0 or 1) the instruction becomes a no-op at runtime (the validity mask is all True). Callers do not need to guard on whether the method has disallowed states.

Parameters:

output_variable (str) – The variable name to attach to the instruction.

Return type:

QuantumInstructionBuilder

Returns:

The builder instance.

frequency_shift(target, frequency)
Return type:

QuantumInstructionBuilder

get_pulse_channel(id)

Given an id, return the corresponding pulse channel.

Checks internally stored pulse channels, but can pull pulse channels from the hardware model if not found.

Return type:

PulseChannel

measure(targets, mode=INTEGRATOR, output_variable=None, sync_qubits=True)

Measure one or more qubits.

Parameters:
  • targets (Qubit | set[Qubit]) – The qubit(s) to be measured.

  • mode (AcquireMode) – The type of acquisition at the level of the control hardware.

  • sync_qubits (bool) – Flag determining whether to align the measurements of all qubits in targets or not. Sync between qubits is on by default.

Return type:

QuantumInstructionBuilder

measure_mean_signal(target, output_variable=None)

Measure the raw IQ signal of a single qubit and return the shot-averaged result.

Emits a MeasureBlock using INTEGRATOR acquisition and appends a PostProcessing(MEAN, SEQUENCE) to average the complex IQ values across all shots. Results are a single complex value per qubit.

Parameters:
  • target (Qubit) – The qubit to be measured.

  • output_variable (Optional[str]) – Name of the variable where the acquire result is saved. A unique name is generated if not provided.

Returns:

The builder instance.

measure_mean_z(target, axis=SEQUENCE, output_variable=None)

Measure a single qubit along the z-axis and return the shot-averaged result.

Emits a MeasureBlock, averages first over the time axis (SCOPE mode only) then over the sequence axis (INTEGRATOR mode only), and finally emits PostProcessing(LINEAR_MAP_COMPLEX_TO_REAL) to project the averaged complex IQ value to a real z-expectation value.

Note

Like measure_single_shot_z(), this method always emits a legacy PostProcessing instruction. Use measure_with_granular_post_processing() for the granular discrimination pipeline.

Parameters:
  • target (Qubit) – The qubit to be measured.

  • axis (ProcessAxis) – The axis along which post-processing of readouts should occur.

  • output_variable (Optional[str]) – Name of the variable where the acquire result is saved. A unique name is generated if not provided.

Returns:

The builder instance.

measure_scope_mode(target, output_variable=None)

Measure the qubit in scope (waveform-capture) mode.

Emits a MeasureBlock using SCOPE acquisition mode. No post-processing is applied; the raw time-series IQ waveform is stored directly in the output variable.

Parameters:
  • target (Qubit) – The qubit to be measured.

  • output_variable (Optional[str]) – Name of the variable where the acquire result is saved. A unique name is generated if not provided.

Returns:

The builder instance.

measure_single_shot_binned(target, axis=SEQUENCE, output_variable=None)

Measure a single qubit along the z-axis and discriminate to ±1 (customer-facing API).

Emits a MeasureBlock, an optional PostProcessing(MEAN, TIME) (SCOPE mode only), PostProcessing(LINEAR_MAP_COMPLEX_TO_REAL) to project complex IQ to a real z-value, and a PostProcessing(DISCRIMINATE) that rounds the z-projection value to +1 (above threshold) or −1 (at or below threshold).

Note

This method uses the legacy DISCRIMINATE post-processing type and does not emit the granular Discriminate instruction used by the post-selection pipeline. It is not equivalent to measure_with_granular_post_processing() (which uses Discriminate/PostSelect) and should not be substituted for it.

Parameters:
  • target (Qubit) – The qubit to be measured.

  • axis (ProcessAxis) – The axis along which post-processing of readouts should occur.

  • output_variable (Optional[str]) – Name of the variable where the acquire result is saved. A unique name is generated if not provided.

Returns:

The builder instance.

measure_single_shot_signal(target, axis=SEQUENCE, output_variable=None)

Measure the raw IQ signal of a single qubit (customer-facing API).

Emits a MeasureBlock and, when axis is TIME (SCOPE mode), an additional PostProcessing(MEAN, TIME) to average over the time axis. No z-discrimination is applied; results are an ndarray of complex IQ values, one per shot.

Parameters:
  • target (Qubit) – The qubit to be measured.

  • axis (ProcessAxis) – The axis along which post-processing of readouts should occur.

  • output_variable (Optional[str]) – Name of the variable where the acquire result is saved. A unique name is generated if not provided.

Returns:

The builder instance.

measure_single_shot_z(target, axis=SEQUENCE, output_variable=None)

Measure a single qubit along the z-axis (customer-facing API).

Emits a MeasureBlock, an optional PostProcessing(MEAN, TIME) when axis is TIME (SCOPE mode), and a PostProcessing(LINEAR_MAP_COMPLEX_TO_REAL) to project the complex IQ value onto a real z-projection. Results are an ndarray of floats centred around 0: values above 0 indicate a bias towards the +Z state, values below 0 indicate a bias towards the −Z state.

Note

This method always emits a legacy PostProcessing instruction regardless of whether post_process_method is configured on the qubit. Compiler frontends that need the granular discrimination pipeline (EqualiseDiscriminatePostSelect) should call measure_with_granular_post_processing() instead (and emit_post_select() for post-selection insertion).

Parameters:
  • target (Qubit) – The qubit to be measured.

  • axis (ProcessAxis) – The axis along which post-processing of readouts should occur. SEQUENCE (default) uses INTEGRATOR acquisition; TIME uses SCOPE acquisition and emits an additional PostProcessing(MEAN, TIME).

  • output_variable (Optional[str]) – Name of the variable where the acquire result is saved. A unique name is generated if not provided.

Returns:

The builder instance.

measure_with_granular_post_processing(target, axis=SEQUENCE, output_variable=None)

Measure a qubit and emit the full granular post-processing pipeline.

This method is intended for use by compiler frontends (QASM2, QASM3, QIR, tket) where the result of a measurement assignment must be discriminated into state labels. Customer-facing code that only needs raw z-projection floats should call measure_single_shot_z() instead.

For qubits with a post_process_method configured the emitted sequence is:

Frontends that need post-selection should append emit_post_select() explicitly based on compiler configuration.

For legacy qubits (post_process_method is None, mean_z_map_args set), emit_granular_post_processing() derives the Equalise rotation from mean_z_map_args and emits the same EqualiseDiscriminate chain so that all measurement paths use one unified pipeline.

Parameters:
  • target (Qubit) – The qubit to be measured.

  • axis (ProcessAxis) – The axis along which post-processing of readouts should occur.

  • output_variable (Optional[str]) – The variable where the acquire result will be saved. A unique name is generated if not provided.

Return type:

QuantumInstructionBuilder

Returns:

The builder instance.

phase_shift(target, theta=3.141592653589793, *args, **kwargs)
post_processing(target, output_variable, process_type, axes=None, args=None)

Emit a legacy PostProcessing instruction.

Populates args automatically when none are provided:

  • LINEAR_MAP_COMPLEX_TO_REAL — reads from target.mean_z_map_args (legacy) or target.post_process_method.mean_z_map_args (new-style LinearMapToRealMethod).

  • DISCRIMINATE — reads from target.discriminator.

Parameters:
  • target (Qubit) – The qubit whose calibration data is used to fill args.

  • output_variable (str) – The variable name to attach to the instruction.

  • process_type (PostProcessType) – The type of post-processing to apply.

  • axes (Union[ProcessAxis, list[ProcessAxis], None]) – Axis or axes along which the post-processing operates.

  • args – Explicit arguments for the post-processing; auto-filled when None for LINEAR_MAP_COMPLEX_TO_REAL and DISCRIMINATE types.

Return type:

QuantumInstructionBuilder

Returns:

The builder instance.

pretty_print()
Return type:

str

pulse(**kwargs)
Return type:

QuantumInstructionBuilder

reset(targets, **kwargs)
Return type:

QuantumInstructionBuilder

swap(target, destination)
Return type:

QuantumInstructionBuilder

synchronize(targets)
Return type:

QuantumInstructionBuilder