# 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>, config=None)

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, either trueq.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 SubstitutionCompiler 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 over-written in the subclass, and should be where the substitutions should be calculated and performed.

Return type

list(Cycles)

class trueq.compilation.Merge(config=None, 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.

Identity gates are removed, and 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 be n_labels=2 etc. This defaults to single qubit reductions.

Parameters

merge_immutable (bool) – If set to True, immutable cycles will be merged, if set to False, 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 over-written in the subclass, and should be where the substitutions should be calculated and performed.

Return type

list(Cycles)

class trueq.compilation.RemoveId(config=None)

Pattern that removes identity gates from 1 trueq.Cycle

This is a good class to use as an example for more complex classes.

This class skips immutable cycles.

Returns 1 Cycles.

apply_cycles(cycles)

In the case of immutable cycles, this class doesn’t remove identity Gates.

class trueq.compilation.SubstitutionCompiler(patterns=None, 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 small 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:

SubstitutionCompiler([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 of trueq.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 or trueq.CircuitCollection

Parameters

circ (trueq.Circuit | trueq.CircuitCollection) – A circuit that the Pattern list should be applied to.

property patterns

A list of all Patterns applied by this compiler.

Return type

list

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 of NativeGates.

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 over-written 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=3, tol=1e-05)

Series of numerical SU(4) decomposition methods.

Decomposes a target gate into a series of SU(2) gates between non-parameterized 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 to 2 * max_depth + 1 Cycles.

Parameters
• config (trueq.Config) – Config object which defines available gates on the system

• max_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 1 trueq.Cycles

Raises

tq.math.DecompError – If there is a gate in the cycle which is not decomposable using the config.

trueq.compilation.get_transpiler(config, rounding=5, tol=0.0001)

Get a SubstitutionCompiler which can transpile from arbitrary TrueQ representation of circuits, into a representation which is compatable with a given config.

This performs a standard set of patterns, and can be used as a template for more advanced compiler definitions.

Parameters
• config (trueq.Config) – A trueq.Config which has 2-qubit gates defined.

• rounding (int) – The number of decimal places to keep in the angles (in degrees) of the KAK decomposition of a two-qubit unitary gate. IE: rounding=0 means that 90.1253 would round to 90, rounding=1 means it would round to 90.1, etc…

• tol (float) – Convergence tolerance on the native 2 qubit decomposition. See Native2Q for more details.