qat.purr.backends.qblox.analysis_passes module

class BindingPass

Bases: AnalysisPass

Builds binding of variables, instructions, and a view of variables from/to scopes.

Variables are implicitly declared in sweep instructions and are ultimately read from quantum instructions. Thus, every iteration variable is associated to all the scopes it is declared in.

Values of the iteration variable are abstract and don’t mean anything. In this pass, we only extract the bound and associate it to the name variable. Further analysis is required on read sites to make sure their usage is consistent and meaningful.

static extract_iter_bound(value)

Given a sequence of numbers (typically having been generated from np.linspace()), figure out if the numbers are linearly/evenly spaced, in which case returns an IterBound instance holding the start, step, end, and count of the numbers in the array, or else fail.

In the future, we might be interested in relaxing this condition and return “interpolated” evenly spaced approximation of the input sequence.

run(ir, res_mgr, *args, **kwargs)
Parameters:
  • ir (QatIR) – The list of instructions stored in an InstructionBuilder.

  • res_mgr (ResultManager) – The result manager to save the analysis results.

class BindingResult(scoping_results=<factory>, rw_results=<factory>, iter_bound_results=<factory>)

Bases: ResultInfoMixin

iter_bound_results: Dict[PulseChannel, Dict[str, IterBound]]
rw_results: Dict[PulseChannel, ReadWriteResult]
scoping_results: Dict[PulseChannel, ScopingResult]
class CFGPass

Bases: AnalysisPass

run(ir, res_mgr, *args, **kwargs)
Parameters:
  • ir (QatIR) – The list of instructions stored in an InstructionBuilder.

  • res_mgr (ResultManager) – The result manager to save the analysis results.

class CFGResult(cfg=<factory>)

Bases: ResultInfoMixin

cfg: ControlFlowGraph
class IterBound(start=None, step=None, end=None, count=None)

Bases: object

count: int = None
end: Union[int, float, complex] = None
start: Union[int, float, complex] = None
step: Union[int, float, complex] = None
class QbloxLegalisationPass

Bases: AnalysisPass

amp_as_steps(amp)

The instruction set_awg_offs expects DAC ratio as a (potentially signed) integer operand. However, This function must return an unsigned integer because registers are unsigned 32bit integers.

Return type:

complex

static freq_as_steps(freq_hz)

The instruction set_freq expects the frequency as a (potentially signed) integer operand. However, This function must return an unsigned integer because registers are unsigned 32bit integers.

Return type:

uint32

static phase_as_steps(phase_rad)

The instruction set_ph_delta expects the phase shift as a (potentially signed) integer operand. However, This function must return an unsigned integer because registers are unsigned 32bit integers.

Return type:

uint32

run(ir, res_mgr, *args, **kwargs)

Performs target-dependent legalisation for QBlox.

  1. A repeat instruction with a very high repetition count is illegal because acquisition memory

on a QBlox sequencer is limited. This requires optimal batching of the repeat instruction into maximally supported batches of smaller repeat counts.

This pass does not do any batching. More features and adjustments will follow in future iterations.

  1. Previously processed variables such as frequencies, phases, and amplitudes still need digital conversion

to a representation that’s required by the QBlox ISA.

  • NCO’s 1GHz frequency range by 4e9 steps:
    • [-500, 500] Mhz <=> [-2e9, 2e9] steps

    • 1 Hz <=> 4 steps

  • NCO’s 360° phase range by 1e9 steps:
    • 1e9 steps <=> 2*pi rad

    • 125e6 steps <=> pi/4 rad

  • Time and samples are quantified in nanoseconds

  • Amplitude depends on the type of the module:
    • [-1, 1] <=> [-2.5, 2.5] V (for QCM)

    • [-1, 1] <=> [-0.5, 0.5] V (for QRM)

  • AWG offset:
    • [-1, 1] <=> [-32 768, 32 767]

The last point is interesting as it requires knowledge of physical configuration of qubits and the modules they are wired to. This knowledge is typically found during execution and involving it early on would upset the rest of the compilation flow. In fact, it complicates this pass in particular, involves allocation concepts that should not be treated here, and promotes a monolithic compilation style. A temporary workaround is to simply assume the legality of amplitudes from the start whereby users are required to convert the desired voltages to the equivalent ratio AOT.

This pass performs target-dependent conversion as described in part (B). More features and adjustments will follow in future iterations.

class ReadWriteResult(reads=<factory>, writes=<factory>)

Bases: object

reads: Dict[str, List[Instruction]]
writes: Dict[str, List[Instruction]]
class ScopingResult(scope2symbols=<factory>, symbol2scopes=<factory>)

Bases: object

scope2symbols: Dict[Tuple[Instruction, Optional[Instruction]], Set[str]]
symbol2scopes: Dict[str, List[Tuple[Instruction, Optional[Instruction]]]]
class TILegalisationPass

Bases: AnalysisPass

An instruction is legal if it has a direct equivalent in the programming model implemented by the control stack. The notion of “legal” is highly determined by the hardware features of the control stack as well as its programming model. Control stacks such as Qblox have a direct ISA-level representation for basic RF instructions such as frequency and phase manipulation, arithmetic instructions such as add, and branching instructions such as jump.

This pass performs target-independent legalisation. The goal here is to understand how variables are used and legalise their bounds. Furthermore, analysis in this pass is fundamentally based on QAT semantics and must be kept target-agnostic so that it can be reused among backends.

Particularly in QAT: #. A sweep instruction is illegal because it specifies unclear iteration semantics. #. Device updates/assigns in general are illegal because they are bound to a sweep

instruction via a variable. In fact, a variable (implicitly defined by a Sweep instruction) remains obscure until a “read” (usually on the instruction builder or on the hardware model) (typically from a DeviceUpdate instruction) is encountered where its intent becomes clear. We say that a DeviceUpdate carries meaning for the variable and materialises its intention.

static decompose_freq(frequency, target)
run(ir, res_mgr, *args, **kwargs)
Parameters:
  • ir (QatIR) – The list of instructions stored in an InstructionBuilder.

  • res_mgr (ResultManager) – The result manager to save the analysis results.

static transform_amp(amp, scale_factor, ignore_scale, target)
class TriagePass

Bases: AnalysisPass

Builds a view of instructions per quantum target AOT.

Builds selections of instructions useful for subsequent analysis/transform passes, for code generation, and post-playback steps.

This is equivalent to the QatFile and simplifies the duration timeline creation in the legacy code.

run(ir, res_mgr, *args, **kwargs)
Parameters:
  • ir (QatIR) – The list of instructions stored in an InstructionBuilder.

  • res_mgr (ResultManager) – The result manager to save the analysis results.

class TriageResult(sweeps=<factory>, returns=<factory>, assigns=<factory>, target_map=<factory>, acquire_map=<factory>, pp_map=<factory>, rp_map=<factory>)

Bases: ResultInfoMixin

acquire_map: Dict[PulseChannel, List[Acquire]]
assigns: List[Assign]
pp_map: Dict[str, List[PostProcessing]]
returns: List[Return]
rp_map: Dict[str, ResultsProcessing]
sweeps: List[Sweep]
target_map: Dict[PulseChannel, List[Instruction]]