Compilation

trueq.compilation.CompilationError

An exception inside of the True-Q™ compiler.

trueq.compilation.CompilePaulis

Pass which adds randomly chosen Pauli gates before all measurements in the circuit.

trueq.compilation.Compiler

Substitutes cycles in a Circuit using a series of Passes.

trueq.compilation.CycleReplacement

Pass that searches Circuits for a specific Cycle and when found, replaces it with a list of provided cycles.

trueq.compilation.InvolvingRestrictions

A pass which ensures that any NativeGate which is defined from a list of GateFactorys obeys the involving restrictions of the GateFactorys.

trueq.compilation.Justify

Pass that moves operations forward in time.

trueq.compilation.MarkCycles

Pass that marks cycles which contain multi-qubit gates if none of the existing cycles in the circuit have been marked with non-zero values.

trueq.compilation.Merge

Pass 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 NCyclePass which iteratively attempts to decompose one-qubit gates into gates which are performable by the given list of GateFactorys.

trueq.compilation.Native1QMode

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

trueq.compilation.Native1QRRZ

An OperationReplacement 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.Native2Q

A NCyclePass which iteratively attempts to decompose two-qubit gates into gates which are performable by the given list of GateFactorys.

trueq.compilation.Native2QCX

An OperationReplacement 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 OperationReplacement which checks if a given operation is a two-qubit gate that is equal to some static GateFactory in the provided list of GateFactorys up to single qubit operations, and if so, switch the Gate with a NativeGate built from the factory list plus the approriate single qubit gates.

trueq.compilation.NativeDecomp

An OperationReplacement which attempts to decompose the target gate using the specified number of gates found in the provided list of GateFactorys.

trueq.compilation.NativeExact

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

trueq.compilation.Parallel

A NCyclePass that splits a cycle into individual operations, passes the operations to provided OperationReplacements in parallel, and recombines the output into a list of cycles.

trueq.compilation.PhaseTrack

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

trueq.compilation.RCCycle

Pass which performs Randomized Compilation on groups of cycles with matching marker values by adding gates on either side of the cycles, chosen using the provided Twirl.

trueq.compilation.Relabel

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

trueq.compilation.RemoveEmptyCycle

Pass which removes empty cycles from groups of cycles with matching markers.

trueq.compilation.RemoveId

Pass that removes single qubit identity gates from 1 Cycle.

trueq.compilation.TryInOrder

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

trueq.compilation.UnmarkCycles

Pass which sets all cycle markers to 0.

trueq.compilation.base.MarkerPass

Parent class for compiler passes which operates on groups of cycles with matching markers.

trueq.compilation.base.NCyclePass

Parent class for compiler passes which accept a fixed number of cycles at a time.

trueq.compilation.base.OperationReplacement

Parent class used by Passes which manipulates a single Operations at a time.

trueq.compilation.base.Pass

Parent class for all Compiler passes that manipulate and return an altered Circuit.

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.

CompilationError

class trueq.compilation.CompilationError

An exception inside of the True-Q™ compiler.

Compiler

class trueq.compilation.Compiler(passes)

Substitutes cycles in a Circuit using a series of Passes.

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

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

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

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

Each Pass object iterates through a circuit in its own way; in the example above, the circuit is iterated over 1 cycle at a time. In general, passes operate on collections of cycles at a time, up to the entire circuit at once. There are two pre-built Pass child classes which define common methods for iterating over a circuit:

  • NCyclePass

    Iterates over a fixed N cycles at a time, the majority of default passes are subclassed off of this.

  • MarkerPass

    Iterates over groups of cycles with matching markers.

An example of iteration is merging multiple single qubit gates into a single operation (which is done by the Merge pass). This requires multiple cycles to be operated on at any given time, in this case this operation can be performed with a fixed number (2) of cycles at a time. The pass 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.

Here is an example of a set of passes which converts a circuit of Gates into a circuit of NativeGates as defined in a Config:

from trueq.compilation import *
import trueq as tq

factories = tq.Config.basic().factories

Compiler(
    [
        Justify(),
        Native2Q(factories=factories),
        Merge(),
        RemoveId(),
        Native1Q(factories=factories),
        Justify(),
    ]
)
Compiler([Justify, Native2Q, Merge, RemoveId, Native1Q, Justify])

This set of passes 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 pass 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 pass 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 pass ensures everything is moved as far forward in the circuit as possible.

Parameters

passes (list) – A list of Passes, see above.

compile(circ)

Sequentially applies all of the passes in the compiler to a given Circuit or CircuitCollection, a new Circuit or CircuitCollection instance is returned.

Parameters

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

Return type

Circuit | CircuitCollection

property passes

A list of all Passes applied by this compiler.

Type

list

static from_config(config, passes=None)

Gets a Compiler which can transpile from arbitrary True-Q™ representation of circuits, into a representation which is compatible with a given config.

By default, this performs a standard set of passes to make the circuit compatible with hardware while making the minimum required changes, and can be used as a template for more advanced compiler definitions. See trueq.compilation.Compiler.HARDWARE_PASSES for a list of the default passes which are applied.

Several other lists of compiler passes are predefined in the compiler. In the example below several of these predefined compiler lists are chained together to randomly compile a circuit containing non-clifford two qubit gates.

import trueq as tq

# define the config which defines hardware gates
config = tq.Config.basic(mode="ZXZ", entangler=tq.Gate.cnot)

# Pick the compiler passes to apply in the specified order. The order below
# will decompose the two qubit gates into the two qubit gates specified in
# the config (which contains clifford entanglers), then randomly compile,
# then convert all gates into hardware compatable gates.
passes = (tq.Compiler.NATIVE2Q_PASSES +
          tq.Compiler.RC_PASSES +
          tq.Compiler.HARDWARE_PASSES)
compiler = tq.Compiler.from_config(config, passes=passes)

# Build the circuit to apply the passes to
circ = tq.Circuit()
circ.append({0: tq.Gate.h})
circ.append({(0, 1): tq.Gate.cnot ** 0.5})
circ.measure_all()

compiler.compile(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:
  • compiled_pauli: XY
  • protocol: RC
  • twirl: Paulis on [0, 1]
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0): z(phi)
Name:
  • z(phi)
Aliases:
  • Gate.id
  • Gate.i
  • Gate.cliff0
Likeness:
  • Identity
Parameters:
  • phi = 0.0
Generators:
  • 'I': 0
Matrix:
  • 1.00 1.00
(1): z(phi)
Name:
  • z(phi)
Aliases:
  • Gate.id
  • Gate.i
  • Gate.cliff0
Likeness:
  • Identity
Parameters:
  • phi = 0.0
Generators:
  • 'I': 0
Matrix:
  • 1.00 1.00
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0): x(phi)
Name:
  • x(phi)
Parameters:
  • phi = 68.822951
Generators:
  • 'X': 68.823
Matrix:
  • 0.83 -0.57j -0.57j 0.83
(1): x(phi)
Name:
  • x(phi)
Parameters:
  • phi = 146.524211
Generators:
  • 'X': 146.524
Matrix:
  • 0.29 -0.96j -0.96j 0.29
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0): z(phi)
Name:
  • z(phi)
Aliases:
  • Gate.id
  • Gate.i
  • Gate.cliff0
Likeness:
  • Identity
Parameters:
  • phi = 0.0
Generators:
  • 'I': 0
Matrix:
  • 1.00 1.00
(1): z(phi)
Name:
  • z(phi)
Aliases:
  • Gate.z
  • Gate.cliff3
Parameters:
  • phi = -180.0
Generators:
  • 'Z': -180.0
Matrix:
  • 1.00j -1.00j
2
Marker 2
Compilation tools may only recompile cycles with equal markers.
(0, 1): cx()
Name:
  • 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
 
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0): z(phi)
Name:
  • z(phi)
Aliases:
  • Gate.id
  • Gate.i
  • Gate.cliff0
Likeness:
  • Identity
Parameters:
  • phi = 0.0
Generators:
  • 'I': 0
Matrix:
  • 1.00 1.00
(1): z(phi)
Name:
  • z(phi)
Aliases:
  • Gate.id
  • Gate.i
  • Gate.cliff0
Likeness:
  • Identity
Parameters:
  • phi = 0.0
Generators:
  • 'I': 0
Matrix:
  • 1.00 1.00
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0): x(phi)
Name:
  • x(phi)
Parameters:
  • phi = 45.0
Generators:
  • 'X': 45.0
Matrix:
  • 0.92 -0.38j -0.38j 0.92
(1): x(phi)
Name:
  • x(phi)
Aliases:
  • Gate.sx
  • Gate.cliff5
Parameters:
  • phi = 90.0
Generators:
  • 'X': 90.0
Matrix:
  • 0.71 -0.71j -0.71j 0.71
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0): z(phi)
Name:
  • z(phi)
Aliases:
  • Gate.cliff8
Parameters:
  • phi = -90.0
Generators:
  • 'Z': -90.0
Matrix:
  • 0.71 0.71j 0.71 -0.71j
(1): z(phi)
Name:
  • z(phi)
Aliases:
  • Gate.id
  • Gate.i
  • Gate.cliff0
Likeness:
  • Identity
Parameters:
  • phi = 0.0
Generators:
  • 'I': 0
Matrix:
  • 1.00 1.00
3
Marker 3
Compilation tools may only recompile cycles with equal markers.
(0, 1): cx()
Name:
  • 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
 
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0): z(phi)
Name:
  • z(phi)
Aliases:
  • Gate.id
  • Gate.i
  • Gate.cliff0
Likeness:
  • Identity
Parameters:
  • phi = 0.0
Generators:
  • 'I': 0
Matrix:
  • 1.00 1.00
(1): z(phi)
Name:
  • z(phi)
Aliases:
  • Gate.z
  • Gate.cliff3
Parameters:
  • phi = 180.0
Generators:
  • 'Z': 180.0
Matrix:
  • -1.00j 1.00j
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0): x(phi)
Name:
  • x(phi)
Aliases:
  • Gate.sx
  • Gate.cliff5
Parameters:
  • phi = 90.0
Generators:
  • 'X': 90.0
Matrix:
  • 0.71 -0.71j -0.71j 0.71
(1): x(phi)
Name:
  • x(phi)
Parameters:
  • phi = 168.475789
Generators:
  • 'X': 168.476
Matrix:
  • 0.10 -0.99j -0.99j 0.10
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0): z(phi)
Name:
  • z(phi)
Parameters:
  • phi = 113.822951
Generators:
  • 'Z': 113.823
Matrix:
  • 0.55 -0.84j 0.55 0.84j
(1): z(phi)
Name:
  • z(phi)
Aliases:
  • Gate.z
  • Gate.cliff3
Parameters:
  • phi = 180.0
Generators:
  • 'Z': 180.0
Matrix:
  • -1.00j 1.00j
1
Marker 1
Compilation tools may only recompile cycles with equal markers.
(0): Meas()
Name:
  • Meas()
(1): Meas()
Name:
  • Meas()
Parameters
Return type

Compiler

static basic(entangler=Gate.cx, mode='ZXZXZ', passes=None)

Gets a Compiler which is built from a standard Config.

By default, this performs a standard set of passes, and a config as defined by trueq.Config.basic(). See trueq.compilation.Compiler.HARDWARE_PASSES for a list of the default passes which are applied.

Parameters
Return type

Compiler

HARDWARE_PASSES = (<class 'trueq.compilation.two_qubit.Native2Q'>, <class 'trueq.compilation.common.Merge'>, <class 'trueq.compilation.one_qubit.Native1Q'>, <class 'trueq.compilation.common.InvolvingRestrictions'>, <class 'trueq.compilation.common.RemoveEmptyCycle'>)

A tuple of compiler passes which decompose all gates into hardware restricted gates while only introducing the minimum number of structural changes to the circuit.

Identity gates are not removed, and are instead compiled into available gates.

Changing this default list changes the behavior of the interfaces to Qiskit, Cirq, and PyQuil, and altering it may break the interface conversions completely.

SIMPLIFY_PASSES = (functools.partial(<class 'trueq.compilation.common.Merge'>, n_labels=2), <class 'trueq.compilation.common.RemoveId'>, <class 'trueq.compilation.common.Justify'>, <class 'trueq.compilation.common.RemoveEmptyCycle'>)

This is a set of compiler passes that merge single/two qubit gates, remove identity gates, and remove empty cycles.

Compiler passes obey markers, meaning simplifications will only happen when neighboring cycles have matching markers.

These passes do not build into NativeGates.

RC_PASSES = (<class 'trueq.compilation.common.MarkCycles'>, <class 'trueq.compilation.common.RCCycle'>, <class 'trueq.compilation.common.CompilePaulis'>, <class 'trueq.compilation.common.Merge'>, <class 'trueq.compilation.common.RemoveEmptyCycle'>)

A tuple of compiler passes that randomly compile a circuit.

This is equivalent to randomly_compile() where n_compilations=1, twirl="P" and compile_paulis=True. These passes do not introduce any NativeGates.

NATIVE2Q_PASSES = (<class 'trueq.compilation.two_qubit.Native2Q'>, <class 'trueq.compilation.common.Merge'>, <class 'trueq.compilation.common.RemoveEmptyCycle'>)

A tuple of compiler passes that decompose two-qubit gates into native gates, and merge all single qubit gates together.

Compiler passes obey markers, so single-qubit gates (including those introduced by Native2Q) will only be merged between neighboring cycles with matching markers.

CompilePaulis

class trueq.compilation.CompilePaulis(factories=None, **_)

Pass which adds randomly chosen Pauli gates before all measurements in the circuit. Additionally updates the circuit key with the compiled_pauli entry with the appropriate Pauli string.

Note

If the circuit’s key already contains a compiled_pauli entry, this entry will be updated to account for the new random Paulis which have been inserted.

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 does 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)
{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

CycleReplacement

class trueq.compilation.CycleReplacement(target, replacement, ignore_marker=True, ignore_id=True, **_)

Pass that searches Circuits for a specific Cycle and when found, replaces it with a list of provided cycles.

import trueq as tq
from trueq.compilation import CycleReplacement

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

# every time the target cycle is found, insert a new cycle before the target
target = tq.Cycle({(0, 1): tq.Gate.cx})
new_cycle = tq.Cycle({0: tq.Gate.from_generators("Z", 4)})

replace_cycle = CycleReplacement(target, replacement=[new_cycle, target])
replace_cycle.apply(old_circuit)

# replacements can also be instantiated with dictionaries instead of cycles
equiv_replace_list = [{0: tq.Gate.from_generators("Z", 4)}, target]
equiv_replace = CycleReplacement({(0, 1): tq.Gate.cx}, equiv_replace_list)
Parameters
  • target (Cycle | dict) – Which cycle to match on.

  • replacement (list | Cycle | dict) – A cycle or list of cycles to replace the target cycle with.

  • ignore_marker (bool) – Whether to apply this pass when the target and a cycle have differing values of trueq.Cycle.marker. Default is True.

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

InvolvingRestrictions

class trueq.compilation.InvolvingRestrictions(factories, **_)

A pass which ensures that any NativeGate which is defined from a list of GateFactorys obeys the involving restrictions of the 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 marker, and marked cycles will be broken into pieces as neccessary.

import trueq as tq

# an example config with no initial restrictions
config = tq.Config.basic(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}])
passes = (tq.compilation.Native2Q, tq.compilation.InvolvingRestrictions)
compiler = tq.Compiler.from_config(config, passes)
compiler.compile(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.
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0, 1): cx()
Name:
  • 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): cx()
Name:
  • 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(factories=None, **_)

Pass that moves operations forward in time.

This class does not move operations between cycles with mismatched markers.

Below is an example where the X gate on qubit 1 is moved forward in time to the end of the circuit:

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: (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

MarkCycles

class trueq.compilation.MarkCycles(marker=None, **_)

Pass that marks cycles which contain multi-qubit gates if none of the existing cycles in the circuit have been marked with non-zero values. By default, markers are start at 1 and increment up for every cycle containing a multi-qubit gate found.

Parameters

marker (int | NoneType) – The marker to be added to cycles containing multi-qubit gates. If None then markers are incremented from 1 for each cycle found.

Merge

class trueq.compilation.Merge(n_labels=1, marker=None, **_)

Pass 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 will only merge gates if adjacent cycles have the same marker.

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.
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
empty
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
empty
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
empty
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(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.

  • marker (int | NoneType) – The cycle marker where this pass will be applied. if None then this pass is applied to all cycles regardless of cycle marker.

MarkerPass

class trueq.compilation.base.MarkerPass(factories=None, **_)

Parent class for compiler passes which operates on groups of cycles with matching markers.

The _apply() method is implemented to invoke the new abstract method _apply_cycles() on every consecutive list of cycles in the circuit with an equal marker.

abstract _apply_cycles(cycles)

Accepts any number of Cycles and returns a list of cycles.

Cycles returned by this function are put back into the original circuit in place of the cycles passed.

There is no restriction on the number of returned cycles.

Parameters

cycles (list) – A list of Cycles which are to be altered by this pass.

Return type

list

Native1Q

class trueq.compilation.Native1Q(factories, mode='ZXZXZ', **_)

A NCyclePass which iteratively attempts to decompose one-qubit gates into gates which are performable by the given list of GateFactorys.

Advanced Users:

This pass 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 replacements, using right-justification if decomposition lengths are ragged:

Parameters
  • factories (Iterable) – The iterable of GateFactory objects containing target one-qubit gates.

  • mode (str) – The single qubit decomposition mode, defaults to 'ZXZXZ', see trueq.math.decomposition.QubitMode for more details.

Native1QRRZ

class trueq.compilation.Native1QRRZ(factories)

An OperationReplacement 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 list which can build either an R gate or Z gate. A GateFactory for R can be found in r_factory.

Parameters

factories (Iterable) – A iterable containing GateFactorys which may contain an R and Z gates as defined above.

Native1QMode

class trueq.compilation.Native1QMode(factories, mode='ZXZXZ', **_)

An OperationReplacement 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 list of GateFactory objects to find one which applies to that qubit. If the found factories are sufficient to build arbitrary single qubit gates according to the target mode. 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
  • factories (Iterable) – The iterable of GateFactory objects containing target one-qubit gates.

  • mode (str) – The single qubit decomposition mode, defaults to 'ZXZXZ', see trueq.math.decomposition.QubitMode for more details.

Native2Q

class trueq.compilation.Native2Q(factories, max_depth=10, tol=1e-12, **_)

A NCyclePass which iteratively attempts to decompose two-qubit gates into gates which are performable by the given list of GateFactorys.

Advanced Users:

This pass 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 replacements, using right-justification if decomposition lengths are ragged:

  • NativeExact -

    See if the gate appears exactly as seen inside of the factory list.

  • Native2QKAK -

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

  • Native2QCX -

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

  • NativeDecomp -

    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 factory list that contains a CZ gate.

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

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

This decomposition is then passed back up to the Native2Q pass (which is a subclass of Parallel), 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
  • factories (Iterable) – The iterable of GateFactory objects containing target two-qubit gates.

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

  • tol (float) – The minimum process infidelity allowed for decompositions to be considered successful, this may be used to do approximate decompositions.

Native2QCX

class trueq.compilation.Native2QCX(factories, **_)

An OperationReplacement 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 OperationReplacement are based on:

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

This pass 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), which includes iSWAP gates.

Parameters

factories (tuple) – The tuple of GateFactory objects.

Native2QKAK

class trueq.compilation.Native2QKAK(factories, **_)

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

Parameters

factories (Iterable) – The iterable of GateFactory objects containing target gates.

NativeDecomp

class trueq.compilation.NativeDecomp(depth, factories, tol=1e-12, max_resets=20, **_)

An OperationReplacement which attempts to decompose the target gate using the specified number of gates found in the provided list of GateFactorys.

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 gates from the factory list to decompose each gate into.

  • factories (tuple) – The tuple of GateFactory objects.

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

  • max_resets (int) – The number of times to attempt to reset the algorithm.

NativeExact

class trueq.compilation.NativeExact(factories, tol=1e-12)

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

Parameters
  • factories (Iterable) – An iterable of GateFactorys which may be used by the replacement.

  • tol (float) – The allowed process infidelity to be considered an exact match.

NCyclePass

class trueq.compilation.base.NCyclePass(factories=None, **_)

Parent class for compiler passes which accept a fixed number of cycles at a time.

This is a convenience parent class which contains the logic of passing a fixed number of cycles n_input_cycles at a time to a child class defined method _apply_cycles(), then taking the returned cycles and re-inserting them into a circuit.

The _apply() method is implemented to invoke the new abstract method _apply_cycles() on every consecutive list of cycles with length equal to n_input_cycles, starting from the beginning of the circuit. At each invocation, the output of _apply_cycles() is inserted into the circuit before calling it on the next subset of cycles. There is no restriction on the number cycles returned by implementations of _apply_cycles().

To demonstrate how this class iterates over cycles, here is an implementation of a pass which takes two cycles at a time, prints the gates, and returns the cycles unaltered:

from trueq.compilation.base import NCyclePass
from trueq import Gate

class Passthrough(NCyclePass):
    n_input_cycles = 2

    def _apply_cycles(self, cycles):
        print([gate for cycle in cycles for _, gate in cycle])
        return cycles

Passthrough().apply([{0: Gate.i}, {0: Gate.x}, {0: Gate.y}, {0: Gate.z}])
[Gate.id, Gate.x]
[Gate.x, Gate.y]
[Gate.y, Gate.z]
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.
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0): Gate.id
Name:
  • Gate.id
Aliases:
  • Gate.id
  • Gate.i
  • Gate.cliff0
Likeness:
  • Identity
Generators:
  • 'I': 0
Matrix:
  • 1.00 1.00
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0): Gate.x
Name:
  • Gate.x
Aliases:
  • Gate.x
  • Gate.cliff1
Generators:
  • 'X': 180.0
Matrix:
  • 1.00 1.00
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0): Gate.y
Name:
  • Gate.y
Aliases:
  • Gate.y
  • Gate.cliff2
Generators:
  • 'Y': 180.0
Matrix:
  • -1.00j 1.00j
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(0): Gate.z
Name:
  • Gate.z
Aliases:
  • Gate.z
  • Gate.cliff3
Generators:
  • 'Z': 180.0
Matrix:
  • 1.00 -1.00

The circuit in this example has four cycles, each with a single gate. The first two cycles which are passed are the ones containing I and X gates. These are printed, and get put back into the circuit without being altered. The pass then increments forward one index and passes the cycles containing X and Y. It is important to note that this increments by one, not n_input_cycles at a time.

abstract _apply_cycles(cycles)

Accepts n_input_cycles number of Cycles and returns a list of cycles.

Cycles returned by this function are put back into the original circuit in place of the cycles passed.

There is no restriction on the number of returned cycles.

Parameters

cycles (list) – A list containing n_input_cycles which are to be altered by this pass.

Return type

list

abstract property n_input_cycles

The number of cycles _apply_cycles() expects.

Type

int

OperationReplacement

class trueq.compilation.base.OperationReplacement

Parent class used by Passes which manipulates a single Operations at a time.

The apply() accepts a label and operation, and returns a list containing dictionaries. This differs from a Pass in that it only operates on a single operation at a time, whereas Passes operate on a cycles or circuits.

abstract apply(labels, operation)

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

The returned list may contain any number of dictionaries.

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

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

Returns

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

Return type

list

Parallel

class trueq.compilation.Parallel(replacements=None, **_)

A NCyclePass that splits a cycle into individual operations, passes the operations to provided OperationReplacements in parallel, and recombines the output into a list of cycles.

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

Each operation in the input cycle is split and passed to each OperationReplacement based upon a dictionary lookup, this dictionary lookup has keys which are labels, and the values are the target OperationReplacement. 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 pass which should be used if the labels are not present in the dictionary.

This returns a list of cycles, where the number of cycles is decided by the OperationReplacements provided, and all cycles returned are joined such that they are justified to the latest possible cycle in time.

All output cycles maintain the marker of the input cycle.

Parameters

replacements (dict | OperationReplacement) – Optional, either a dictionary mapping labels to OperationReplacements, or just a single OperationReplacement, which is applied to all labels.

Pass

class trueq.compilation.base.Pass(factories=None, **_)

Parent class for all Compiler passes that manipulate and return an altered Circuit.

A pass accepts a circuit to its apply() function. This circuit will then be operated on, and some (potentially new) circuit is returned.

abstract _apply(circuit)

Applies the pass to a circuit, the original circuit may be altered in place.

The apply() method will call this after correctly formatting the circuit, and logging the execution time of the pass.

Parameters

circuit (Circuit) – The circuit to which the pass will be applied.

Returns

A circuit that has been altered by the pass.

Return type

Circuit

apply(circuit)

Applies the pass to a circuit, the original circuit may be altered in place.

Parameters

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

Returns

A circuit that has been altered by the pass.

Return type

Circuit

PhaseTrack

class trueq.compilation.PhaseTrack(factories, virtual=None, include_final_virtual=False, **_)

This pass 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 pass 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 pass 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
  • factories (Iterable) – An iterable of GateFactorys that contains all the gate factories of interest.

  • virtual (NoneType | GateFactory) – The factory of the virtual gate. By default, the factory list wil 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.

RCCycle

class trueq.compilation.RCCycle(twirl='P', **_)

Pass which performs Randomized Compilation on groups of cycles with matching marker values by adding gates on either side of the cycles, chosen using the provided Twirl.

Use of this class requires a Randomized Compilation license.

Note

Cycles containing twirling gates are inserted before and after blocks of cycles which have non-zero markers. The inserted cycles will have the default marker 0.

Multiple cycles in a row which all contain the same marker value are twirled around as a group, twirls are not inserted between the cycles.

No twirling gates are added around groups of cycles containing Meas or Prep operations.

Parameters

twirl (trueq.Twirl | str) – The Twirl to use. You can also specify a twirling group (default is "P") that will be used to automatically instantiate a twirl based on the labels in the given circuit.

Relabel

class trueq.compilation.Relabel(permutation, **_)

Pass 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.
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
(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(preserve_marker=True, **_)

Pass which removes empty cycles from groups of cycles with matching markers.

By default if the group of cycles contain no Operations at all, this will return a single empty cycle with the original marker.

Parameters

preserve_marker (bool) – Whether to disable this pass from removing a group of cycles altogether, if they are all empty, for the sake of preserving the marker value. If True (default), in such a case, one empty cycle will be kept with the marker value of the group.

RemoveId

class trueq.compilation.RemoveId(marker=0, **_)

Pass 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.
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
empty
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
empty
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
empty
 
Marker 0
Compilation tools may only recompile cycles with equal markers.
empty
Parameters

marker (int | NoneType) – The cycle marker where this pass will be applied. if None then this pass is applied to all cycles regardless of cycle marker.

TryInOrder

class trueq.compilation.TryInOrder(replacements=None, **_)

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

All replacements in TryInOrder must be OperationReplacements.

Parameters

replacements (list) – Optional, a list of OperationReplacements to be applied in order until one succeeds.

append(replacement)

Appends a replacement to the list of existing replacements.

Parameters

replacement (OperationReplacement) – The replacement to be appended.

apply(label, operation)

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

The returned list may contain any number of dictionaries.

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

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

Returns

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

Return type

list

UnmarkCycles

class trueq.compilation.UnmarkCycles(factories=None, **_)

Pass which sets all cycle markers to 0.