Compilation¶

class
trueq.compilation.
Direction
¶ Defines the two directions that Patterns may be applied to
trueq.Circuit
See descrption of
trueq.compilation.base.Pattern
for more details

class
trueq.compilation.
Justify
(direction=<Direction.FORWARD: 1>, **_)¶ Pattern that takes two Cycles, and moves gates preferentially to one side.
This method is inherently limited, because it only deals with 2 Cycles at a time, it can encounter “traffic jams”, IE: If you have two Cycles on qubit 0, followed by a series of empty cycles, the first Cycles Gate cannot move because of the second Cycle, but then the second cycle’s Gate will iteratively progress forward through the empty Cycles. This can be combated by repeating the Justify several times.
This class skips immutable cycles.
Returns 2 Cycles.
 Parameters
direction (
trueq.compilation.base.Direction
) – Specifies the direction to preferentially move gates, eithertrueq.compilation.base.Direction.FORWARD
or BACK

property
direction
¶ This must return the direction that the pattern will be applied.
Direction must be one of the two enums of
trueq.compilation.base.Direction
This requires some discussion, the way that the Compiler functions is that it incrementally goes through a circuit, and passes a set of Cycles to a Pattern. There are two ways that it can increment through the Circuit, Forward or Backward.

apply_cycles
(cycles)¶ This must accept n_input_cycles number of Cycles and return a list of Cycles.
This function must be overwritten in the subclass, and should be where the substitutions should be calculated and performed.
 Return type
list(Cycles)

class
trueq.compilation.
Merge
(n_labels=1, merge_immutable=False, **_)¶ Pattern that takes two cycles, finds compatabile labels and gates, then merges them to a single gate as much as is possible.
Gates are automatically split into the smallest number of individual gates possible. For example, if the merging results in a two qubit gate that turns out to be the kronecker product of two single qubit gates, then it will automatically be broken apart into the two single qubit gates.
This class skips immutable cycles unless specified.
Returns 2 Cycles.
 Params n_labels
How many labels to merge at any given time, if only single qubit reductions are desired, then
n_labels=1
, two qubit reductions would ben_labels=2
etc. This defaults to single qubit reductions. Parameters
merge_immutable (
bool
) – If set toTrue
, immutable cycles will be merged, if set toFalse
, then immutable cycles are skipped.

apply_cycles
(cycles)¶ This must accept n_input_cycles number of Cycles and return a list of Cycles.
This function must be overwritten in the subclass, and should be where the substitutions should be calculated and performed.
 Return type
list(Cycles)

class
trueq.compilation.
RemoveId
(skip_immutable=True, **_)¶ Pattern that removes identity gates from 1
trueq.Cycle
This is a good class to use as an example for more complex classes.
Returns a list containing 1 Cycle.
 Params skip_immutable
Determines if identity gates should be removed from immutable cycles. If
True
, immutable cycles are not altered.

apply_cycles
(cycles)¶ Removes all identity gates in a cycle if the cycle is mutable or skip_immutable is
False
.

class
trueq.compilation.
Relabel
(permutation, **_)¶ Pattern which relabels all the labels and keys in a circuit.
This searches through and relabels/reorders entries in the following key entries:
analyze_decays
compiled_pauli
cycle
measurement_basis
targeted_errors
twirl
Note that this does not function when the circuit has results present.
# Swapping the labels on qubit 0 and 1, 2 stays permutation = {0: 1, 1: 0, 2: 2} pat = Relabel(permutation) new_circ = pat.apply_cycles(old_circ)
 Parameters
permutation (
dict
) – A dictionary where the keys are the current label and the values are the new labels.

apply_cycles
(circuit)¶ This must accept n_input_cycles number of Cycles and return a list of Cycles.
This function must be overwritten in the subclass, and should be where the substitutions should be calculated and performed.
 Return type
list(Cycles)

class
trueq.compilation.
CycleSandwich
(target, before=None, after=None, ignore_imm=True, ignore_id=True)¶ Pattern that searches circuits for a specific cycle and when found, sandwiches it between two other (optional) cycles.
target = tq.Cycle({(0, 1): tq.Gate.CNOT}) before = tq.Cycle(0: tq.Gate.from_generators("Z", 4)) after = tq.Cycle(1: tq.Gate.from_generators("X", 8.2)) pattern = CycleSandwich(target, before=before, after=after) new_circ = pattern.apply_cycles(old_circuit)
Note
This pattern makes deep copies of before and after before returning them.
 Parameters
target (
Cycle
) – Which cycle to match on.before (
Cycle
) – A cycle to place immediately before every occurrence of the provided target.after (
Cycle
) – A cycle to place immediately after every occurrence of the provided target.ignore_imm (
bool
) – Whether to apply this pattern when the target and a cycle have differing values oftrueq.Cycle.immutable
. Default isTrue
.ignore_id (
bool
) – Whether to treat all identity gates as though they are not present when comparing cycles. Default isTrue
.

apply_cycles
(cycles)¶ This must accept n_input_cycles number of Cycles and return a list of Cycles.
This function must be overwritten in the subclass, and should be where the substitutions should be calculated and performed.
 Return type
list(Cycles)

class
trueq.compilation.
InvolvingRestrictions
(config=None)¶ A Pattern which ensures that any
trueq.NativeGate
that is defined from a config obeys the involving restrictions of itsFactory
.This is done through a greedy algorithm, with no guarantee on optimal number of final cycles.
Returns a list of cycles, whose length will not exceed the number of operations inside the original cycle.
Cycles retain their immutable flag, and immutable cycles will be broken into pieces as neccessary.
import trueq as tq import trueq.compilation as tqc # config is a tq.Config which has arbitrary involving restrictions on any gate cycle = tq.Cycle({(0, 1): tq.Gate.cx, (2, 3): tq.Gate.cx, 7: tq.Gate.x}) patterns = [tqc.Native2Q(config), tqc.InvolvingRestrictions(config)] comp = tq.compilation.Compiler(patterns) comp.compile([cycle])

apply_cycles
(cycles)¶ This must accept n_input_cycles number of Cycles and return a list of Cycles.
This function must be overwritten in the subclass, and should be where the substitutions should be calculated and performed.
 Return type
list(Cycles)


class
trueq.compilation.
Compiler
(patterns, repeat=1)¶ Substitutes cycles in a Circuit using known substitution Patterns.
In classical computing this would formally be called a Peephole Optimizer.
This stores a list of
trueq.compilation.base.Pattern
objects which are rules for how to replace Gates in sets of cycles.These Pattern objects take a set of cycles at a time, and return an altered set of cycles. A trivial example is the
RemoveId()
pattern, which accepts 1 cycle at a time, and removes any identity Gates from the cycle, before returning it.Each Pattern object requires a certain number of cycles at a time; in the example above, only 1 cycle is passed. In general this is not the case, for example to simplify single qubit operations. In this case the minimum number of cycles needed is 2. The Pattern looks for single qubit gates in both of the cycles, and computes the single equivalent Gate, which is put back instead of the two original Gates.
In traversing a Circuit, the compiler can either iterate forward, or backward. This traversal direction is specified by the Patterns themselves, as it may be useful to have certain patterns apply themselves backwards while others are strictly forward.
To build a Compiler which knows all possible simplification rules would result in an overly complex and rigid tool, which would would be difficult to generalize for all hardware implementations. By making the compiler itself very small, and allowing custom rulesets (Patterns in this case), very complex compilation instructions can be expressed in simple and readable fashion.
An example of a set of patterns which converts a Circuit into hardware aware Gates:
 Compiler([Justify(),
Native2Q(config=config), Merge(), RemoveId(), Native1Q(config=config), Justify() ])
This set of patterns performs these operations:
 Justify  move gates preferentially to one side of the circuit, for example,
A circuit containing an X90 Gate at the beginning, but then 10 empty cycles. Justify(Direction.FORWARD) would move the X90 gate all the way to the other end of the circuit.
 Native2Q  Convert all 2 qubit operations found in the circuit into NativeGate’s
which can be run on a hardware as specified by the config object. This Pattern does NOT decompose the single qubit gates, so in the process it adds single qubit Gate objects to some Cycles.
 Merge  This simplifies any neighboring single qubit operations and reduces
them to a single Gate.
 RemoveId  Since the simplify step may have introduced single qubit gate which
are the identity gate, this Pattern removes all Id Gates.
 Native1Q  This converts all 1 qubit operations into NativeGates which can be
run on hardware as specified by the config object.
 Justify  Just for good measure, make sure everything is moved as far forward
in the Circuit as Possible.
 Parameters
patterns (
list
) – A list oftrueq.compilation.base.Pattern
, see above.repeat (
int
) – The number of times to repeat the pattern list, may be helpful in certain instances.

compile
(circ)¶ Apply all of the patterns in the compiler in order to a given
trueq.Circuit
ortrueq.CircuitCollection
 Parameters
circ (
trueq.Circuit
trueq.CircuitCollection
) – A circuit that the Pattern list should be applied to.

property
patterns
¶ A list of all
Pattern
s applied by this compiler. Return type
list

trueq.compilation.
count_streaks
(circuit)¶ Iterates through a circuit, finding all multiqudit gates and counting the number of times that there are repeated operations on the same pair of qudits.
Repeated operations on a pair of qudits can often be merged and do not require extra swaps to map a circuit onto a specific chip topology. Therefore we want to count “streaks”, where a “streak” on a pair of qudits is a series of cycles in a circuit where the qudit pair of interest do not interact with any other qudits.
For example: Given a circuit of 6 cnot gates, where there are 2 cnots in a row on (0, 1) followed by a cnot on (1, 2), then 3 more cnots in a row on (0, 1).
On labels (0, 1) there is 1 streak of 2 in a row and 1 of 3 in a row. On labels (1, 2) there is 1 streak of length 1.
circ = tq.Circuit({(0, 1): tq.Gate.cx}) circ.add_cycle({(0, 1): tq.Gate.cx}) circ.add_cycle({(1, 2): tq.Gate.cx}) circ.add_cycle({(0, 1): tq.Gate.cx}) circ.add_cycle({(1, 0): tq.Gate.cx}) circ.add_cycle({(0, 1): tq.Gate.cx}) count_streaks(circ) # {(0, 1): {2: 1, 3: 1}, (1, 2): {1: 1}}
This function returns a nested dictionary whose keys are pairs of qudits that have a multiqudit gate acting on them, and the values are the numbers of streaks of each length. In the above example, (0, 1) has a value of
`{2: 1, 3: 1}`
, meaning it found 1 streak of length 2 and 1 streak of length 3.Note that single qudit operations will not break a streak, and operations may happen in parallel and those will be counted as independent streaks.
The keys of the dictionary can be used to define the connectivity graph of the circuit itself, and are useful for validation of matching circuit topology to chip topology.
 Parameters
circuit (
trueq.Circuit
) – The circuit of which to calculate the topology and streaks. Return type
dict

class
trueq.compilation.
Native1Q
(config)¶ Pattern which expands arbitrary single qubit gates into the decomposition mode provided in a given
Config
object. Basics of operation:
1. When asked to decompose a qubit gate on a given label, looks through the config object to find
GateFactory
objects that apply to that qubit. Checks if these factories are sufficient to build arbitrary single qubit gates according to the mode of the config. This list of factories is stashed against the label.2. Next, these factories are combined with
QubitMode
to decompose into 3 or 5 cycles ofNativeGate
s.
This class does NOT skip immutable cycles.
Returns 3 or 5 cycles.
 Parameters
config (
trueq.Config
) – Config object which defines available gates on the system

apply_cycles
(cycles)¶ This must accept n_input_cycles number of Cycles and return a list of Cycles.
This function must be overwritten in the subclass, and should be where the substitutions should be calculated and performed.
 Return type
list(Cycles)

class
trueq.compilation.
Native2Q
(config, max_depth=3, rounding=5, tol=1e06)¶ Series of numerical SU(4) decomposition methods.
Decomposes a target gate into a series of SU(2) gates between nonparameterized SU(4) gates found in the config. This uses the
trueq.math.decomposition.decompose_su4()
method found below.This class does NOT skip immutable cycles.
Returns
1
to2 * max_depth + 1
Cycles. Parameters
config (
trueq.Config
) – Config object which defines available gates on the systemmax_depth (
int
) – The maximum number of SU(4) gates to use.rounding (
int
) – How much rounding should be performed on the KAK fitting, this is how many decimal places to round to in terms of degrees, IE: 0 means nearest whole degree, 1 means nearest 0.1 degree etc.

apply_cycles
(cycles)¶ Decomposes all SU(4) gates in a given cycle into gates defined by the config.
 Parameters
cycles (
list
) – A list containing 1trueq.Cycle
s Raises
tq.math.DecompError – If there is a gate in the cycle which is not decomposable using the config.

class
trueq.compilation.
PhaseTrack
(config, virtual=None)¶ This pattern tracks phase accumulation on each qudit throughout a circuit, and compiles this phase information into parametric gates.
For example, if a device tunes up two gate pulses, \(X90\) and \(XX90\) (the maximally entangling MolmerSorensen gate), and implements singlequbit Zrotations virtually, then this pattern will accumulate phases on each qubit based on \(Z(\theta)\) gates it finds, and respectively replace \(X90\) and \(XX90\) gates with parameterized \(X90(\phi)\) gates (i.e. 90 degree nutations about a vector in the XY plane) and parameterized \(XX90(\phi_1, \phi_2)\) gates (i.e. the \(XX90\) gate which has been individually phase updated on each qubit). Therefore, pulse sequences can be programmed directly by looping through cycles in a circuit, choosing the pulse shape based on the gate names, and choosing pulse phases based on the parameters of the gates.
See Phase Tracking with the Compiler for detailed usage examples.
Note
This pattern may not output a circuit that implements the same unitary as the input because it may be off by zrotations (as in the example above) prior to measurement. It will, however, produce the same bitstring statistics because a zrotation prior to a measurement along the zaxis will not affect bitstring populations.
 Parameters
config (
Config
) – The config object that contains all the gate factories of interest.virtual (
None
GateFactory
) – The factory of the virtual gate. By default, the config will be searched for a singlequbit Zrotation, which will be defined as the virtual gate.

apply
(cycles)¶ This applies the Pattern to a collection of Cycles.
This accepts a
trueq.Circuit
,list
, ordict
 Parameters
cycles (
trueq.Circuit
,list
,dict
) – A set of Cycles (n_input_cycles or more)

apply_cycles
(cycles)¶ This must accept n_input_cycles number of Cycles and return a list of Cycles.
This function must be overwritten in the subclass, and should be where the substitutions should be calculated and performed.
 Return type
list(Cycles)

class
trueq.compilation.
DecomposeRRZ
(config=None)¶ Decomposes single qubit gates into 3 gates \(R(\theta) R(\phi) Z(\gamma)\), where the R gates are defined by \(Z(\theta) X(90) Z(\theta)\).
This does not build into
trueq.NativeGate
s, it is a direct decomposition fromtrueq.Gate
s intotrueq.Gate
s. All other operations are left unchanged in the final cycle which is returned.This class does not skip immutable cycles.
It accepts 1 cycle and will return either 1 or 3 cycles.

apply_cycles
(cycles)¶ This must accept n_input_cycles number of Cycles and return a list of Cycles.
This function must be overwritten in the subclass, and should be where the substitutions should be calculated and performed.
 Return type
list(Cycles)


trueq.compilation.
compile
(config, circuit, patterns=None)¶ Compile from arbitrary TrueQᵀᴹ representation of circuits, into a representation which is compatable with a given config.
By default, this performs a standard set of patterns, and can be used as a template for more advanced compiler definitions. See trueq.compilation.DEFAULT_PATTERNS for a list of the default patterns which are applied.
 Parameters
config (
trueq.Config
) – Atrueq.Config
which has 2qubit gates defined.circuit (
trueq.Circuit
) – A circuit which will be compiled into the config compatable format.patterns (
tuple
) – A tuple oftrueq.compilation.Pattern
to be applied in order. These must be uninstantiated classes which must accept a config as a keyword argument, see trueq.compilation.DEFAULT_PATTERNS for an example. If None is provided, then the default list is used.

trueq.compilation.
get_transpiler
(config, patterns=None)¶ Get a
trueq.Compiler
which can transpile from arbitrary TrueQᵀᴹ representation of circuits, into a representation which is compatable with a given config.By default, this performs a standard set of patterns, and can be used as a template for more advanced compiler definitions. See trueq.compilation.DEFAULT_PATTERNS for a list of the default patterns which are applied.
 Parameters
config (
trueq.Config
) – Atrueq.Config
which has 2qubit gates defined.patterns (
tuple
) – A tuple oftrueq.compilation.Pattern
to be applied in order. These must be uninstantiated classes which must accept a config as a keyword argument, see trueq.compilation.DEFAULT_PATTERNS for an example. If None is provided, then the default list is used.