qat.backend.passes.analysis 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¶ (
InstructionBuilder
) – The list of instructions stored in anInstructionBuilder
.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
]
-
iter_bound_results:
- class CFGPass
Bases:
AnalysisPass
- run(ir, res_mgr, *args, **kwargs)
- Parameters:
ir¶ (
InstructionBuilder
) – The list of instructions stored in anInstructionBuilder
.res_mgr¶ (
ResultManager
) – The result manager to save the analysis results.
- class CFGResult(cfg=<factory>)
Bases:
ResultInfoMixin
-
cfg:
ControlFlowGraph
-
cfg:
- class IntermediateFrequencyAnalysis(model)
Bases:
AnalysisPass
Adapted from
qat.purr.backends.live.LiveDeviceEngine.build_baseband_frequencies()
.Retrieves intermediate frequencies for all physical channels if they exist, and validates that pulse channels that share the same physical channel cannot have differing fixed frequencies. This pass should always follow a
TriagePass
, as information of pulse channels are needed.Instantiate the pass with a hardware model.
- Parameters:
model¶ (
QuantumHardwareModel
) – The hardware model.
- run(ir, res_mgr, *args, **kwargs)
- Parameters:
ir¶ (
PartitionedIR
) – The list of instructions stored in anInstructionBuilder
.res_mgr¶ (
ResultManager
) – The result manager to store the analysis results.
- Return type:
- class IntermediateFrequencyResult(frequencies)
Bases:
ResultInfoMixin
-
frequencies:
Dict
[PhysicalChannel
,float
]
-
frequencies:
- 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
-
count:
- class LifetimePass
Bases:
AnalysisPass
The end goal of this pass is to facilitate sequencer allocation on the control hardware. Much like classical register allocation techniques, this pass is intended to perform “channel liveness” analysis.
A logical channel is alive at some point P1 in the builder (analogically to a classical program) if it is targeted by some quantum operation at some point P2 > P1 in the future relative to P1.
Example:
- P1: |– builder.pulse(pulse_channel1)
- …
- P2: | builder.pulse(pulse_channel2) –|
- … |
- P3: |– builder.pulse(pulse_channel1) |
… |
P4: builder.pulse(pulse_channel2) –|
pulse_channel1 is alive at P1 and P2, pulse_channel2 is alive at P2 and P3. Notice how the lifetimes of the channels overlap and “interfere”.
Knowledge of channel/target liveness (with full awareness of control flow) is invaluable for understanding physical allocation requirements on the control stack. This is achieved via an interference graph which allows allocation to be represented as a graph coloring.
With this in mind, this pass spits out a colored interference graph that will be used by the code generator.
- run(ir, res_mgr, *args, **kwargs)
- class PulseChannelTimeline(samples=<factory>, start_positions=<factory>, end_positions=<factory>)
Bases:
object
Timeline analysis for instructions on a pulse channel.
Imagine the timeline for a pulse channel, with an instruction that occurs over samples 3-7, i.e.,
samples: 0 1 2 [3 4 5 6 7] 8 9 10.
The start_position would be 3, the end_position 7, and the number of samples 5.
- Parameters:
-
end_positions:
ndarray
[int
]
-
samples:
ndarray
[int
]
-
start_positions:
ndarray
[int
]
- class ReadWriteResult(reads=<factory>, writes=<factory>)
Bases:
object
-
reads:
Dict
[str
,List
[Instruction
]]
-
writes:
Dict
[str
,List
[Instruction
]]
-
reads:
- class ScopingResult(scope2symbols=<factory>, symbol2scopes=<factory>)
Bases:
object
-
scope2symbols:
Dict
[Tuple
[Instruction
,Optional
[Instruction
]],Set
[str
]]
-
symbol2scopes:
Dict
[str
,List
[Tuple
[Instruction
,Optional
[Instruction
]]]]
-
scope2symbols:
- 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¶ (
InstructionBuilder
) – The list of instructions stored in anInstructionBuilder
.res_mgr¶ (
ResultManager
) – The result manager to save the analysis results.
- static transform_amp(amp, scale_factor, ignore_scale, target)
- class TimelineAnalysis
Bases:
AnalysisPass
Analyses the timeline of each pulse channel.
Takes the instruction list for each pulse channel retrieved from the the partitioned results, and calculates the timeline in units of samples (each sample takes time sample_time). It calculates the duration of each instruction in units of samples, and the start and end times of each instruction in units of samples.
Warning
The pass will assume that the durations of instructions are sanitised to the granularity of the channels. If instructions that do not meet the criteria are provided, it might produce incorrect timelines. This can be enforced used the
InstructionGranularitySanitisation
pass.- static durations_as_samples(channel, durations)
Converts a list of durations into a number of samples.
- run(ir, res_mgr, *args, **kwargs)
- Parameters:
ir¶ (
PartitionedIR
) – The list of instructions stored in anInstructionBuilder
.res_mgr¶ (
ResultManager
) – The result manager to store the analysis results.
- Return type:
- class TimelineAnalysisResult(target_map=<factory>, total_duration=0.0)
Bases:
ResultInfoMixin
Stores the timeline analysis for all pulse channels.
- Parameters:
target_map¶ (
dict
[PulseChannel
,PulseChannelTimeline
]) – The dictionary containing the timeline analysis for all pulse channels.
-
target_map:
dict
[PulseChannel
,PulseChannelTimeline
]
-
total_duration:
float
= 0.0
- 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¶ (
InstructionBuilder
) – The list of instructions stored in anInstructionBuilder
.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
]]
-
pp_map:
Dict
[str
,List
[PostProcessing
]]
-
rp_map:
Dict
[str
,ResultsProcessing
]
-
target_map:
Dict
[PulseChannel
,List
[Instruction
]]
-
acquire_map: