Compilation

trueq.compilation.base.Pattern

Parent class for substitution patterns used by the Compiler which manipulate and return lists of Cycles.

trueq.compilation.base.OperationPattern

Parent class for substitution patterns used by the Compiler which manipulate single Operations at a time.

trueq.compilation.CompilationError

An exception inside of the True-Q™ compiler.

trueq.compilation.Compiler

Substitutes cycles in a Circuit using substitution Patterns.

trueq.compilation.count_streaks

Iterates through a Circuit, finding all multi-qubit gates and counting the number of times that there are repeated operations on the same pair of qubits.

trueq.compilation.CycleSandwich

Pattern that searches Circuits for a specific Cycle and when found, sandwiches it between two other (optional) cycles.

trueq.compilation.DEFAULT_PATTERNS

This is the default set of compiler patterns.

trueq.compilation.Direction

Defines the two directions in which Patterns may be applied to a Circuit.

trueq.compilation.InvolvingRestrictions

A pattern which ensures that any NativeGate that is defined from a Config obeys the involving restrictions of its GateFactorys.

trueq.compilation.Justify

Pattern that takes two Cycles, and moves gates preferentially to one side.

trueq.compilation.Merge

Pattern that takes two cycles, finds compatabile labels and gates, then merges them to a single gate as much as is possible.

trueq.compilation.Native1Q

A Pattern which iteratively attempts to decompose one-qubit gates into gates which are performable by the given Config.

trueq.compilation.Native1QRRZ

An OperationPattern which 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)\) in time.

trueq.compilation.Native1QMode

An OperationPattern which expands arbitrary single qubit gates into the decomposition mode provided in a given Config.

trueq.compilation.Native1QUGates

An OperationPattern which decomposes single qubit gates into U1, U2, or U3 gates found inside of the provided Config.

trueq.compilation.Native2Q

A Pattern which iteratively attempts to decompose two-qubit gates into gates which are performable by the given Config.

trueq.compilation.Native2QCX

An OperationPattern which decomposes any SU(4) into a gate which is locally equivalent to CNOT, as long as such a gate exists inside of the given Config.

trueq.compilation.Native2QKAK

An OperationPattern which checks if a given operation is a two-qubit gate that is equal to some static GateFactory in the provided Config up to single qubit operations, and if so, switch the Gate with a NativeGate from the config plus the approriate single qubit gates.

trueq.compilation.Native2QFastDecomp

An OperationPattern which attempts to decompose the provided gate up to a given depth using gates found in the provided Config.

trueq.compilation.NativeExact

Checks to see if each gate is present in the provided Config exactly as defined, and if so, switch the Gate with a NativeGate from the config.

trueq.compilation.Parallel

A Pattern that splits a cycle into individual operations, passes the operations to other patterns in parallel, and recombines the output into a list of cycles.

trueq.compilation.PhaseTrack

This pattern tracks phase accumulation on each qubit throughout a circuit, and compiles this phase information into parametric gates.

trueq.compilation.Relabel

Pattern which relabels all the labels and keys in a Circuit.

trueq.compilation.RemoveEmptyCycle

Pattern which accepts one cycle and only returns it if it’s not empty.

trueq.compilation.RemoveId

Pattern that removes single qubit identity gates from 1 Cycle.

trueq.compilation.TryInOrder

An OperationPattern where a list of OperationPatterns is stored, and each is attempted in order until no CompilationError is raised.

trueq.compile

Compiles an arbitrary Circuit into a representation which is compatible with a given Config.

CompilationError

class trueq.compilation.CompilationError

An exception inside of the True-Q™ compiler.

Compiler

class trueq.compilation.Compiler(patterns, repeat=1)

Substitutes cycles in a Circuit using substitution Patterns.

In classical computing this would formally be called a Peephole Optimizer.

An instance of this class stores a list of Pattern objects which define rules for how to decompose, replace, or remove Gates (or more generally, Operations) in a fixed number of cycles, while possibly also adding, removing, or mutating cycles.

A simple example is the RemoveId pattern, which accepts 1 cycle at a time, and removes any identity gates from the cycle, before returning it.

To build a Compiler which knows all possible simplification rules would result in an overly complex and rigid tool, which would be difficult to generalize for all hardware implementations. By making the compiler itself very small, and allowing custom rules (Patterns in this case), very complex compilation instructions can be expressed in a simple and readable fashion.

Each Pattern object requires a certain number of cycles at a time; in the example above, only 1 cycle is passed. In general many patterns accept more than 1, for example merging multiple single qubit gates into a single operation requires multiple cycles to be passed into the Merge pattern. 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.

Each pattern iterates through a circuit forward or backward depending on the directionspecified by the pattern.

An example of a set of patterns which converts a circuit of Gates into a circuit of NativeGates as defined in a Config.

from trueq.compilation import *
import trueq as tq

config = tq.Config.basic("example")

Compiler(
    [
        Justify(),
        Native2Q(config=config),
        Merge(),
        RemoveId(),
        Native1Q(config=config),
        Justify(),
    ]
)
Compiler([Justify(n_cycles=2), Native2Q(n_cycles=1), Merge(n_cycles=2), RemoveId(n_cycles=1), Native1Q(n_cycles=1), Justify(n_cycles=2)])

This set of patterns performs these operations:

Justify

Move gates preferentially to one side of the circuit. For example, if a circuit contains an X90 gate at the beginning and 10 empty cycles, Justify would move the X90 gate to the end of the circuit.

Native2Q

Convert all two qubit operations found in the circuit into NativeGates which can be run on 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. Changing the default settings can enable it to merge multi-qubit gates together as well.

RemoveId

Since the merge step may have introduced single qubit gates which could be identity gates, this pattern removes all identity gates.

Native1Q

This converts all one-qubit operations into NativeGates which can be run on hardware as specified by the config object.

Justify

To leave everything in the ground state for as long as possible, this pattern ensures everything is moved as far forward in the circuit as possible.

Parameters
  • patterns (list) – A list of Patterns, see above.

  • repeat (int) – The number of times to repeat the pattern list, defaults to 1.

compile(circ)

Sequentially apply all of the patterns in the compiler to a given Circuit or CircuitCollection

Parameters

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

Return type

Circuit | CircuitCollection

property patterns

A list of all Patterns applied by this compiler.

Return type

list

count_streaks

class trueq.compilation.count_streaks(circuit)

Iterates through a Circuit, finding all multi-qubit gates and counting the number of times that there are repeated operations on the same pair of qubits.

Repeated operations on a pair of qubits 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 qubits is a series of cycles in a circuit where the qubit pair of interest do not interact with any other qubits.

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.

import trueq as tq
circ = tq.Circuit({(0, 1): tq.Gate.cx})
circ.append({(0, 1): tq.Gate.cx})
circ.append({(1, 2): tq.Gate.cx})
circ.append({(0, 1): tq.Gate.cx})
circ.append({(1, 0): tq.Gate.cx})
circ.append({(0, 1): tq.Gate.cx})
circ.draw()

tq.compilation.count_streaks(circ)
0 1 2 Key: Imm Labels: (0, 1) Name: Gate.cx Aliases: Gate.cx Gate.cnot Locally Equivalent: CNOT Generators: ZI: 90.00 ZX: -90.00 IX: 90.00 1.00 1.00 1.00 1.00 CX CX Imm Labels: (0, 1) Name: Gate.cx Aliases: Gate.cx Gate.cnot Locally Equivalent: CNOT Generators: ZI: 90.00 ZX: -90.00 IX: 90.00 1.00 1.00 1.00 1.00 CX CX Imm Labels: (1, 2) Name: Gate.cx Aliases: Gate.cx Gate.cnot Locally Equivalent: CNOT Generators: ZI: 90.00 ZX: -90.00 IX: 90.00 1.00 1.00 1.00 1.00 CX CX Imm Labels: (0, 1) Name: Gate.cx Aliases: Gate.cx Gate.cnot Locally Equivalent: CNOT Generators: ZI: 90.00 ZX: -90.00 IX: 90.00 1.00 1.00 1.00 1.00 CX CX Imm Labels: (1, 0) Name: Gate.cx Aliases: Gate.cx Gate.cnot Locally Equivalent: CNOT Generators: ZI: 90.00 ZX: -90.00 IX: 90.00 1.00 1.00 1.00 1.00 CX CX Imm Labels: (0, 1) Name: Gate.cx Aliases: Gate.cx Gate.cnot Locally Equivalent: CNOT Generators: ZI: 90.00 ZX: -90.00 IX: 90.00 1.00 1.00 1.00 1.00 CX CX
{frozenset({0, 1}): {2: 1, 3: 1}, frozenset({1, 2}): {1: 1}}

This function returns a nested dictionary whose keys are pairs of qubits that have a multi-qubit 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 qubit 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

CycleSandwich

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.

import trueq as tq

old_circuit = tq.Circuit({(0, 1): tq.Gate.cx})

# every time a the target cycle is found, add the before and after cycles as
# appropriate
target = tq.Cycle({(0, 1): tq.Gate.cx})
before = tq.Cycle({0: tq.Gate.from_generators("Z", 4)})
after = tq.Cycle({1: tq.Gate.from_generators("X", -8.2)})

pattern = tq.compilation.CycleSandwich(target, before=before, after=after)
pattern.apply(old_circuit)
True-Q formatting will not be loaded without trusting this notebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking "File -> Trust Notebook".
Circuit
Key:
No key present in circuit.
 
 
(0): Gate(Z)
Name:
  • Gate(Z)
Generators:
  • 'Z': 4.0
Matrix:
  • 1.00 -0.03j 1.00 0.03j
imm
(0, 1): Gate.cx
Name:
  • Gate.cx
Aliases:
  • Gate.cx
  • Gate.cnot
Likeness:
  • CNOT
Generators:
  • 'IX': 90.0
  • 'ZI': 90.0
  • 'ZX': -90.0
Matrix:
  • 1.00 1.00 1.00 1.00
 
(1): Gate(X)
Name:
  • Gate(X)
Generators:
  • 'X': -8.2
Matrix:
  • 1.00 0.07j 0.07j 1.00

Note

This pattern makes deep copies of before and after.

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 of trueq.Cycle.immutable. Default is True.

  • ignore_id (bool) – Whether to treat all identity gates as though they are not present when comparing cycles. Default is True.

DEFAULT_PATTERNS

compilation.DEFAULT_PATTERNS = (<class 'trueq.compilation.two_qubit.Native2Q'>, <class 'trueq.compilation.common.Justify'>, <class 'trueq.compilation.common.Merge'>, <class 'trueq.compilation.common.RemoveId'>, <class 'trueq.compilation.common.RemoveEmptyCycle'>, <class 'trueq.compilation.one_qubit.Native1Q'>, functools.partial(<class 'trueq.compilation.common.RemoveId'>, skip_immutable=False), <class 'trueq.compilation.common.InvolvingRestrictions'>, <class 'trueq.compilation.common.RemoveEmptyCycle'>)

Direction

class trueq.compilation.Direction(value)

Defines the two directions in which Patterns may be applied to a Circuit.

See the description of Pattern for more details.

FORWARD = 1
BACK = 2

InvolvingRestrictions

class trueq.compilation.InvolvingRestrictions(config)

A pattern which ensures that any NativeGate that is defined from a Config obeys the involving restrictions of its GateFactorys.

Returns a list of Cycles, whose length will not exceed the number of operations inside the original cycle.

Satisfying the involving restrictions is done through a greedy algorithm, and there is no guarantee that the final number of cycles will be optimal.

Cycles retain their immutable flag, and immutable cycles will be broken into pieces as neccessary.

import trueq as tq

# an example config with no initial restrictions
config = tq.Config.basic("example", entangler=tq.Gate.cx)

# adding a restriction on cx on (0, 1) so that it can not be at the
# same time as gates on qubit (2, )
config.cx.involving[(0, 1)] = (2, )

circuit = tq.Circuit([{(0, 1): tq.Gate.cx, (2, 3): tq.Gate.cx, 7: tq.Gate.x}])
patterns = (tq.compilation.Native2Q, tq.compilation.InvolvingRestrictions)
tq.compile(config, circuit, patterns)
True-Q formatting will not be loaded without trusting this notebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking "File -> Trust Notebook".
Circuit
Key:
No key present in circuit.
     
imm
(0, 1): GateFactory.cx()
Name:
  • GateFactory.cx
Aliases:
  • Gate.cx
  • Gate.cnot
Likeness:
  • CNOT
Generators:
  • 'IX': 90.0
  • 'ZI': 90.0
  • 'ZX': -90.0
Matrix:
  • 1.00 1.00 1.00 1.00
(2, 3): GateFactory.cx()
Name:
  • GateFactory.cx
Aliases:
  • Gate.cx
  • Gate.cnot
Likeness:
  • CNOT
Generators:
  • 'IX': 90.0
  • 'ZI': 90.0
  • 'ZX': -90.0
Matrix:
  • 1.00 1.00 1.00 1.00
(7): Gate.x
Name:
  • Gate.x
Aliases:
  • Gate.x
  • Gate.cliff1
Generators:
  • 'X': 180.0
Matrix:
  • 1.00 1.00

Justify

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.

import trueq as tq

circuit = tq.Circuit()
circuit.append({0: tq.Gate.id, 1: tq.Gate.x})
circuit.append({0: tq.Gate.id})
circuit.append({0: tq.Gate.id})
circuit.draw()

pat = tq.compilation.Justify()
pat.apply(circuit).draw()
0 1 Key: Labels: (0,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID Labels: (1,) Name: Gate.x Aliases: Gate.x Gate.cliff1 Generators: X: 180.00 1.00 1.00 X Labels: (0,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID Labels: (0,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID
0 1 Key: Labels: (0,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID Labels: (0,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID Labels: (0,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID Labels: (1,) Name: Gate.x Aliases: Gate.x Gate.cliff1 Generators: X: 180.00 1.00 1.00 X
Parameters

direction (trueq.compilation.Direction) – Specifies the direction to preferentially move gates, either FORWARD or BACK.

Merge

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.

import trueq as tq

# Make a circuit containing 4 x gates in a row, and merge them together
circuit = tq.Circuit()
for _ in range(4):
    circuit.append({0: tq.Gate.x})

pat = tq.compilation.Merge()
pat.apply(circuit)
True-Q formatting will not be loaded without trusting this notebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking "File -> Trust Notebook".
Circuit
Key:
No key present in circuit.
 
   
   
   
 
(0): Gate.id
Name:
  • Gate.id
Aliases:
  • Gate.id
  • Gate.i
  • Gate.cliff0
Likeness:
  • Identity
Generators:
  • 'I': 0
Matrix:
  • 1.00 1.00
Parameters
  • n_labels (int) – How many labels to merge at any given time, if only single qubit merging is desired, then n_labels=1, merging two qubit operations would be n_labels=2 etc. This defaults to single qubit reductions.

  • merge_immutable (bool) – If set to True, immutable cycles will be merged, if set to False, then immutable cycles are skipped.

Native1Q

class trueq.compilation.Native1Q(config)

A Pattern which iteratively attempts to decompose one-qubit gates into gates which are performable by the given Config.

Advanced Users:

This pattern combines Parallel and TryInOrder to attempt various one-qubit decomposition methods across one-qubit gates in a given cycle. In particular, every one-qubit gate will attempt to be decomposed, in order, by the following patterns, using right-justification if decomposition lengths are ragged:

  • NativeExact -

    See if the gate appears exactly as seen inside of the config.

  • Native1QUGates -

    Decompose single qubit gates into U gates if they are defined inside of the config.

  • Native1QMode -

    Decompose single qubit gates into the mode defined inside of the config, as long as the config defines the correct gates.

  • Native1QRRZ -

    Decompose single qubit gates into R and Z gates, as long as the config defines the correct gates.

Parameters

config (Config) – The Config object containing target one-qubit gates.

Native1QRRZ

class trueq.compilation.Native1QRRZ(config=None)

An OperationPattern which 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)\) in time.

This will return either 1 or 3 dictionaries.

Will throw a CompilationError if no GateFactory can be found in the config which can build either an R gate or Z gate. A GateFactory for R can be found in r_factory.

Parameters

config (Config) – A config object potentially containing GateFactorys which represent R and Z gates as defined above.

Native1QMode

class trueq.compilation.Native1QMode(config=None)

An OperationPattern which expands arbitrary single qubit gates into the decomposition mode provided in a given Config.

Basics of operation:

  1. When decomposing a single qubit gate on a given label, this 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 cached against the label.

  2. Next, these factories are combined with QubitMode to decompose into 3 or 5 dictionaries of NativeGates.

Returns 1, 3, or 5 dictionaries.

Parameters

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

Native1QUGates

class trueq.compilation.Native1QUGates(config=None)

An OperationPattern which decomposes single qubit gates into U1, U2, or U3 gates found inside of the provided Config.

This will return a list containing 1 dictionary.

Parameters

config (Config) – A config object potentially containing GateFactorys which represent U gates as defined in u1_factory, u2_factory, u3_factory.

Native2Q

class trueq.compilation.Native2Q(config, max_depth=3)

A Pattern which iteratively attempts to decompose two-qubit gates into gates which are performable by the given Config.

Advanced Users:

This pattern combines Parallel and TryInOrder to attempt various two-qubit decomposition methods across two-qubit gates in a given cycle. In particular, every two-qubit gate will attempt to be decomposed, in order, by the following patterns, using right-justification if decomposition lengths are ragged:

  • NativeExact -

    See if the gate appears exactly as seen inside of the config.

  • Native2QKAK -

    See if the gate is equivalent to a gate inside of the config up to single qubit operations.

  • Native2QCX -

    If a CX equivalent gate is found in the config, build the target gate using a known analytic decomposition.

  • Native2QFastDecomp -

    Use a numerical method to find a decomposition, a very general method.

Walking through an example:

Lets start with a cycle which only contains a single Haar random SU(4), with a config that contains a CZ gate.

Each operation is passed to the TryInOrder one a time, the TryInOrder pattern will run through its list of patterns, starting with NativeExact until no errors occur.

Since the target gate is Haar random and the config only defines a CZ, the first few patterns will fail. The first pattern which will successfully decompose the random gate in this case will be the Native2QCX, as the config defines a CZ which is locally equivalent to CX.

This decomposition is then passed back up to the Native2Q pattern (which is a subclass of the Parallel pattern), where it has no other cycles to be combined with, so it is simply returned as is. See Parallel for more details on how cycles are combined in general.

Parameters
  • config (Config) – The Config object containing target two qubit gates.

  • max_depth (int) – The maximum depth passed to the final numerical decomposition method Native2QFastDecomp.

Native2QCX

class trueq.compilation.Native2QCX(config=None)

An OperationPattern which decomposes any SU(4) into a gate which is locally equivalent to CNOT, as long as such a gate exists inside of the given Config.

The decomposition methods inside of this Pattern are based on:

https://arxiv.org/abs/quant-ph/0307177

This pattern accepts 1 operation, and will return either 5 or 7 dictionaries, see Native2QKAK if only 3 dictionaries are expected.

If the target gate is locally equivalent to a gate of the form trueq.Gate.from_generators("XX", theta, "YY", phi) for any phi or theta, then the restrictions on the config defined gate relax from being locally equivalent to a CNOT to any gate of the form trueq.Gate.from_generators("XX", 90, "YY", phi).

Parameters

config (Config) – The config to look in for possible gates.

Native2QFastDecomp

class trueq.compilation.Native2QFastDecomp(depth, config, tol=1e-08)

An OperationPattern which attempts to decompose the provided gate up to a given depth using gates found in the provided Config.

This is only successful if the provided gate can be decomposed in exactly the depth specified and the decomposition has a process infidelity which is smaller than the tol parameter.

Parameters
  • depth (int) – The number of two qubit gates from the config which to decompose each gate into.

  • config (Config) – The config to look in for possible gates.

  • tol (float) – The minimum process infidelity allowed for the decomposition to be considered successful.

Native2QKAK

class trueq.compilation.Native2QKAK(config)

An OperationPattern which checks if a given operation is a two-qubit gate that is equal to some static GateFactory in the provided Config up to single qubit operations, and if so, switch the Gate with a NativeGate from the config plus the approriate single qubit gates.

Parameters

config (Config) – The config to look in for possible gates.

NativeExact

class trueq.compilation.NativeExact(config=None)

Checks to see if each gate is present in the provided Config exactly as defined, and if so, switch the Gate with a NativeGate from the config.

Parameters

config (Config) – The config to look in for possible gates.

OperationPattern

class trueq.compilation.base.OperationPattern(config=None)

Parent class for substitution patterns used by the Compiler which manipulate single Operations at a time.

The apply() accepts a label and operation, and returns a list containing dictionaries. This differs from a Pattern in that it only operates on a single operation at a time, whereas a Pattern operates on a cycle, and returns a list of cycles.

Parameters

config (Config) – A Config which may be used by the pattern.

abstract apply(labels, operation)

This accepts labels and a Operation and returns a list of dictionaries, where the dictionary keys are labels and the values are Operations.

Parameters
  • labels (tuple) – A tuple containing the qubit labels which the operation acts on.

  • operation (trueq.Operation) – The operation to be altered by the pattern.

Returns

A list of dictionaries, where the keys are labels, and the values are trueq.Operations.

Return type

list

Parallel

class trueq.compilation.Parallel(pattern_dict=None, **kwargs)

A Pattern that splits a cycle into individual operations, passes the operations to other patterns in parallel, and recombines the output into a list of cycles.

Note that this pattern is not implemented in parallel across cpu cores currently.

Each operation in the input cycle is split and passed to each sub-pattern based upon a dictionary lookup, this dictionary lookup has keys which are labels, and the values are the target OperationPattern. If the given labels are not found in the lookup dictionary, then the operation is passed unaltered to the output cycles. The lookup dictionary can optionally have a None key, which signifies a default pattern which should be used if the labels are not present in the dictionary.

All patterns in Parallel must be OperationPatterns.

This returns a list of cycles, where the number of cycles is decided by the patterns provided, and all cycles returned by the patterns are joined such that they are justified to the latest possible cycle in time. All output cycles maintain the immutablility flag of the input cycle.

Parameters
  • pattern_dict (dict) – Optional, a dictionary mapping labels to OperationPatterns.

  • kwargs (dict) – No kwargs are used, but has to be present for compatibility.

Pattern

class trueq.compilation.base.Pattern(config=None)

Parent class for substitution patterns used by the Compiler which manipulate and return lists of Cycles.

A pattern will be passed a list of cycles in order to it’s apply_cycles() function. It will then perform it’s substitution and return a list of Cycles. The number of cycles passed to the pattern is decided by the n_input_cycles property.

There is no restriction on the number of returned cycles.

Patterns should be subclassed off of this class, and implement at a minimum:

See those functions for descriptions of expected inputs and outputs.

abstract property n_input_cycles

Returns the number of cycles this pattern expects.

This must be over-written in the subclass, but doesn’t neccessarily need to be a function.

# an example where this is not defined as a function
class Example(Pattern):
    n_input_cycles = 1
Return type

int

abstract 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 are applied.

Return type

list

abstract property direction

The direction in which the compiler will iterate while applying the pattern.

The Compiler can iterate through a Circuit either forward or backward, passing a portion of the circuit to the Pattern as it iterates.

This direction must be specified by one of the two enums of Direction, namely, FORWARD or BACK.

apply(circuit)

Applies the pattern to a circuit.

Parameters

circuit (Circuit | Cycle list | dict) – The circuit to which the pattern will be applied.

Returns

A new circuit that has been altered by the pattern.

Return type

Circuit

PhaseTrack

class trueq.compilation.PhaseTrack(config, virtual=None, include_final_virtual=False)

This pattern tracks phase accumulation on each qubit 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 Molmer-Sorensen gate), and implements single-qubit Z-rotations 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 X-Y 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 z-rotations (as in the example above) prior to measurement. It will, however, produce the same bitstring statistics because a z-rotation prior to a measurement along the z-axis 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 single-qubit Z-rotation, which will be defined as the virtual gate.

  • include_final_virtual (bool) – Whether to apply the cumulative virtual gates prior to preparations, measurements, or at the end of the circuit.

Relabel

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.

import trueq as tq

old_circ = tq.Circuit([{0: tq.Gate.x, 1: tq.Gate.y, 2: tq.Gate.z}])

# Swapping the labels on qubit 0 and 1, 2 stays
permutation = {0: 1, 1: 0, 2: 2}

pat = tq.compilation.Relabel(permutation)
pat.apply(old_circ)
True-Q formatting will not be loaded without trusting this notebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking "File -> Trust Notebook".
Circuit
Key:
No key present in circuit.
     
 
(0): Gate.y
Name:
  • Gate.y
Aliases:
  • Gate.y
  • Gate.cliff2
Generators:
  • 'Y': 180.0
Matrix:
  • -1.00j 1.00j
(1): Gate.x
Name:
  • Gate.x
Aliases:
  • Gate.x
  • Gate.cliff1
Generators:
  • 'X': 180.0
Matrix:
  • 1.00 1.00
(2): Gate.z
Name:
  • Gate.z
Aliases:
  • Gate.z
  • Gate.cliff3
Generators:
  • 'Z': 180.0
Matrix:
  • 1.00 -1.00
Parameters

permutation (dict) – A dictionary where the keys are the current label and the values are the new labels.

RemoveEmptyCycle

class trueq.compilation.RemoveEmptyCycle(config=None)

Pattern which accepts one cycle and only returns it if it’s not empty.

RemoveId

class trueq.compilation.RemoveId(skip_immutable=True, **_)

Pattern that removes single qubit identity gates from 1 Cycle.

Returns a list containing 1 Cycle.

import trueq as tq

# Make a circuit containing 4 id gates in a row
circuit = tq.Circuit()
for _ in range(4):
    circuit.append({0: tq.Gate.id})

# remove all identity gates
pat = tq.compilation.RemoveId()
pat.apply(circuit)
True-Q formatting will not be loaded without trusting this notebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking "File -> Trust Notebook".
Circuit
Key:
No key present in circuit.
 
 
 
 
Parameters

skip_immutable (bool) – Determines if identity gates should be removed from immutable cycles. If True, immutable cycles are not altered.

TryInOrder

class trueq.compilation.TryInOrder(patterns=None, **kwargs)

An OperationPattern where a list of OperationPatterns is stored, and each is attempted in order until no CompilationError is raised.

All patterns in TryInOrder must be OperationPatterns.

Parameters
  • patterns (list) – Optional, a list of OperationPatterns to be applied in order until one succeeds.

  • kwargs (dict) – No kwargs are accepted, but has to be present for compatibility.

append(pattern)

Append a pattern to the list of existing patterns.

Parameters

pattern (OperationPattern) – The pattern to be appended.

apply(label, operation)

This accepts labels and a Operation and returns a list of dictionaries, where the dictionary keys are labels and the values are Operations.

Parameters
  • labels (tuple) – A tuple containing the qubit labels which the operation acts on.

  • operation (trueq.Operation) – The operation to be altered by the pattern.

Returns

A list of dictionaries, where the keys are labels, and the values are trueq.Operations.

Return type

list

compile

trueq.compile(config, circuit, patterns=None)

Compiles an arbitrary Circuit into a representation which is compatible 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 DEFAULT_PATTERNS for a list of the default patterns which are applied.

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

  • circuit (trueq.Circuit) – A circuit which will be compiled into the config compatable format.

  • patterns (tuple) – A tuple of Pattern to be applied in order. These must be uninstantiated classes which must accept a config as a keyword argument, see DEFAULT_PATTERNS for an example. If None is provided, then this default list is used.