# Compilation

 trueq.compilation.AllocateLabels Relabels a Circuit to match the labels and topology of a Graph. trueq.compilation.BestCostDecomposer Decomposes gates by applying the DecompStrategy with the lowest cost. 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.CPhaseStrategy Performs optimal decomposition of two-qubit gates into 0, 1, 2, or 3 CPHASE gates, defined below. trueq.compilation.CPhaseXYJointStrategy Combines the CPhaseStrategy and the XYStrategy strategies for input gates that can be created using one of each gate. trueq.compilation.CycleReplacement Pass that searches Circuits for a specific Cycle and when found, replaces it with a list of provided cycles. trueq.compilation.DeferredSwapper Inserts swaps and decomposes gates of a Circuit to obey the connectivity of Graph. 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.MarkBlocks Pass that marks cycles which contain multi-qubit gates if none of the existing non-measurement cycles in the circuit have been marked with non-zero values. 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 a list of cycles, finds compatabile labels and gates, and 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 An OperationReplacement which checks if the specified gate can be generated directly from a single output of a single factory present in the GateFactory list with an appropriate choice of parameter values, and if so, replaces a Gate with the NativeGate. trueq.compilation.OneQuditDecomp A pass which decomposes cycles of arbitrary single-qudit gates into alternations of cycles of native gates with diagonal gates. 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 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 (RC) on groups of cycles with matching marker values by adding gates on either side of the cycles, chosen using the provided Twirl. trueq.compilation.RCKak Pass which performs Randomized Compilation (RC) on cycles with non-zero markers. trueq.compilation.RCLocal Pass which performs Randomized Compilation (RC) on groups of cycles with matching marker values by adding gates on either side of the cycles. trueq.compilation.Relabel Pass which relabels all the labels and keys in a Circuit. trueq.compilation.RemarkCycles Pass that remarks all the marked cycles. 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 one 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.XYStrategy Performs optimal decomposition of two-qubit gates into 0, 1, 2, or 3 XY gates, defined below. 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.decomposition_strategy.GateAttr Abstract base for classes that hold properties about a gate that are relevant to particular decomposition strategies. trueq.compilation.decomposition_strategy.KakAttr Stores the KAK decomposition of a Gate. trueq.compilation.decomposition_strategy.FactoryNoiseTopology Mixin for decomposition strategies that use a single GateFactory to produce entanglement, and that make use of a label-based cost function to quantify the quality of a decomposition. trueq.compilation.decomposition_strategy.DecompStrategy Abstract parent classes that are able to provide a cost heuristic for decomposing gates in terms of other gates, and that also perform the decomposition when requested. 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.decompose_clifford Decomposes a Clifford into a circuit of one- and two-qudit gates. trueq.compilation.decompose_control Decomposes the provided Gate as a smaller unitary acting on a subset of qubits conditioned on a particular bitstring on the remaining qubits.

## Base Classes

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:

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.

import trueq as tq

# make a simple one-qubit circuit with four X gates
circuit = tq.Circuit([{0: tq.Gate.x}] * 4)

# Create a compiler with a Merge pass
compiler = tq.Compiler([tq.compilation.Merge()])

# this compiler will merge all four X gates into a single
# identity operation
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): Gate.id Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Likeness: Identity Generators: 'I': 0 Matrix: 1.00 1.00
Parameters

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

Return type
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: XX 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.z Gate.cliff3 Parameters: phi = 180.0 Generators: 'Z': 180.0 Matrix: -1.00j 1.00j (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) Parameters: phi = 136.416451 Generators: 'X': 136.416 Matrix: 0.37 -0.93j -0.93j 0.37 (1): x(phi) Name: x(phi) Parameters: phi = 58.715191 Generators: 'X': 58.715 Matrix: 0.87 -0.49j -0.49j 0.87 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: 'ZX': -90.0 'IX': 90.0 'ZI': 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.z Gate.cliff3 Parameters: phi = 180.0 Generators: 'Z': 180.0 Matrix: -1.00j 1.00j (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) Parameters: phi = 135.0 Generators: 'X': 135.0 Matrix: 0.38 -0.92j -0.92j 0.38 (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.s Gate.sz Gate.cliff9 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: 'ZX': -90.0 'IX': 90.0 'ZI': 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) 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 = 166.284809 Generators: 'X': 166.285 Matrix: 0.12 -0.99j -0.99j 0.12 Marker 0 Compilation tools may only recompile cycles with equal markers. (0): z(phi) Name: z(phi) Parameters: phi = 88.583549 Generators: 'Z': 88.584 Matrix: 0.72 -0.70j 0.72 0.70j (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'>, max_sys=2), <class 'trueq.compilation.common.RemoveId'>, <class 'trueq.compilation.common.Justify'>, <class 'trueq.compilation.common.RemoveEmptyCycle'>)

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.rc.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.

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

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

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)

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

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

## Decomposition Strategy

class trueq.compilation.decomposition_strategy.GateAttr

Abstract base for classes that hold properties about a gate that are relevant to particular decomposition strategies.

These properties may be expensive to compute, and this read-only container can serve as a shared resource.

abstract static from_gate(gate)

Returns a new GateAttr constructed from a gate.

Parameters

gate (Gate) – The gate to construct from.

Return type

GateAttr

class trueq.compilation.decomposition_strategy.KakAttr(a, b, k)

Stores the KAK decomposition of a Gate.

The KAK decomposition is relatively expensive compared to many compiler operations such as gate multiplication, and this read-only container can serve as a shared resource for the compiler.

The assertion in the following example defines the requirements of the decomposition. In particular the values of x, y, z = k are expected to be in degrees, not radians, and such that the correct core arises when passed to from_generators(). Additionally, the Weyl chamber convention used should satisfy $90 \geq x \geq y \geq |z|$ and $z>0$ whenever $x=90$.

import trueq as tq

g = tq.Gate.random(4)
kak = tq.compilation.decomposition_strategy.KakAttr.from_gate(g)

x, y, z = kak.k
core = tq.Gate.from_generators("XX", x, "YY", y, "ZZ", z)

assert g == (kak.a0 & kak.a1) @ core @ (kak.b0 & kak.b1)

Parameters
• a (tuple) – The pair of single qubit gates on the left of the KAK decomposition.

• b (tuple) – The pair of single qubit gates on the right of the KAK decomposition.

• k (numpy.ndarray) – The three angles of the core of the KAK decomposition.

static from_gate(gate)

Returns a new KakAttr constructed from a gate.

Parameters

gate (Gate) – The gate to construct from.

Return type

KakAttr

property a

The pair of single qubit gates on the left of the KAK decomposition.

Type

tuple

property b

The pair of single qubit gates on the right of the KAK decomposition.

Type

tuple

property gate

The gate this is a KAK decomposition of.

Type

Gate

The KAK core angles in radians, including an entry for the II element.

Type

numpy.ndarray

property x_zero

Whether the XX component of the core is approximately zero.

Type

bool

property y_zero

Whether the YY component of the core is approximately zero.

Type

bool

property z_zero

Whether the ZZ component of the core is approximately zero.

Type

bool

property xy_equal

Whether the XX and YY components of the core are approximately equal.

Type

bool

property yz_equal

Whether the XX and ZZ components of the core are approximately equal.

Type

bool

class trueq.compilation.decomposition_strategy.FactoryNoiseTopology(noise_topology, factory=None, scalings=None, special_cases=None)

Mixin for decomposition strategies that use a single GateFactory to produce entanglement, and that make use of a label-based cost function to quantify the quality of a decomposition.

Parameters
• noise_topology (dict) – A dictionary mapping label tuples to gate quality, which is a number in $[0, 1]$, where 0 indicates perfect quality.

• factory (GateFactory | NoneType) – The factory used by this strategy.

• scalings (list | NoneType) – A scaling factor for each factory parameter in case it is equivalent to DEFAULT up to some scalings. For example, if the default factory has a parameters in terms of degrees but the factory you want is in terms of radians, you can provide a scaling for each parameter to do this conversion.

• special_cases (Iterable) – An iterable of Gates and/or zero-parameter GateFactorys that specify special values of the possibly-parametric factory that you may want to treat specially during circuit conversion or scheduling.

DEFAULT: GateFactory

The default GateFactory to use if one is not provided during construction.

property factory

The factory used by this strategy.

Type

GateFactory

native_gate(*args)

Returns the Gate provided gate factory arguments, preferring an element of special_cases if it exists.

Parameters

*args – Arguments to be forwarded to factory.

Return type

Gate

unit_cost(labels)

The cost of one application of factory on the provided labels, which is a number in $[0, 1]$, where 0 indicates perfect quality.

Parameters

labels (tuple) – The labels to hypothetically apply the gate to.

Return type

float

class trueq.compilation.decomposition_strategy.DecompStrategy

Abstract parent classes that are able to provide a cost heuristic for decomposing gates in terms of other gates, and that also perform the decomposition when requested.

SPEC

The input type to cost() and decompose() that encapsulates gate properties that shouldn’t be computed more than once.

alias of GateAttr

abstract cost(labels, gate_spec)

Estimates a cost for performing this kind of decomposition on the provided gate.

The cost is a number in $[0,1]$ where a small number indicates that this is a good strategy, and a value 1 indicates that it is impossible.

Parameters
Return type

float

abstract decompose(labels, gate_spec)

Decomposes the provided gate into a list (in circuit order) of dictionaries that map labels to gates.

Parameters
Return type

float

class trueq.compilation.CPhaseStrategy(noise_topology, factory=None, scalings=None, special_cases=None)

Performs optimal decomposition of two-qubit gates into 0, 1, 2, or 3 CPHASE gates, defined below. See FactoryNoiseTopology for a description of the constructor arguments.

$\begin{split}\operatorname{CPHASE}(\phi)= \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & \exp(i\phi\pi/90) \end{pmatrix}\end{split}$
SPEC

alias of KakAttr

DEFAULT: GateFactory = GateFactory(name='cphase', layers=[Rotation(<matrix>, 'phi')], parameters={'phi': None})

The default GateFactory to use if one is not provided during construction.

cost(labels, gate_spec)

Estimates a cost for performing CPHASE decomposition on the provided gate.

The cost is a number in $[0,1]$ where a small number indicates that this is a good strategy, and a value 1 indicates that it is impossible.

Parameters
• labels (tuple) – The labels of the gate to decompose.

• gate_spec (GateAttr) – The gate to decompose, encapsulated as a SPEC.

Return type

float

decompose(labels, gate_spec)

Decomposes the provided gate into a list (in circuit order) of dictionaries that map labels to gates.

Parameters
• labels (tuple) – The labels of the gate to decompose.

• gate_spec (GateAttr) – The gate to decompose, encapsulated as a SPEC.

Return type

float

Raises

CompilationError – If the provided gate on the provided labels cannot be decomposed.

class trueq.compilation.XYStrategy(noise_topology, factory=None, scalings=None, special_cases=None)

Performs optimal decomposition of two-qubit gates into 0, 1, 2, or 3 XY gates, defined below. See FactoryNoiseTopology for a description of the constructor arguments.

$\begin{split}\operatorname{XY}(\phi)= \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos(\phi\pi/180) & i\sin(\phi\pi/180) & 0 \\ 0 & i\sin(\phi\pi/180) & \cos(\phi\pi/180) & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}\end{split}$
SPEC

alias of KakAttr

DEFAULT: GateFactory = GateFactory(name='xy', layers=[Rotation(<matrix>, 'phi')], parameters={'phi': None})

The default GateFactory to use if one is not provided during construction.

cost(labels, gate_spec)

Estimates a cost for performing XY decomposition on the provided gate.

The cost is a number in $[0,1]$ where a small number indicates that this is a good strategy, and a value 1 indicates that it is impossible.

Parameters
• labels (tuple) – The labels of the gate to decompose.

• gate_spec (GateAttr) – The gate to decompose, encapsulated as a SPEC.

Return type

float

decompose(labels, gate_spec)

Decomposes the provided gate into a list (in circuit order) of dictionaries that map labels to gates.

Parameters
• labels (tuple) – The labels of the gate to decompose.

• gate_spec (GateAttr) – The gate to decompose, encapsulated as a SPEC.

Return type

float

Raises

CompilationError – If the provided gate on the provided labels cannot be decomposed.

class trueq.compilation.CPhaseXYJointStrategy(cphase_strategy, xy_strategy)

Combines the CPhaseStrategy and the XYStrategy strategies for input gates that can be created using one of each gate.

Parameters
SPEC

alias of KakAttr

cost(labels, gate_spec)

Estimates a cost for performing joint CPHASE and XY decomposition on the provided gate.

The cost is a number in $[0,1]$ where a small number indicates that this is a good strategy, and a value 1 indicates that it is impossible.

Parameters
• labels (tuple) – The labels of the gate to decompose.

• gate_spec (GateAttr) – The gate to decompose, encapsulated as a SPEC.

Return type

float

decompose(labels, gate_spec)

Decomposes the provided gate into a list (in circuit order) of dictionaries that map labels to gates.

Parameters
• labels (tuple) – The labels of the gate to decompose.

• gate_spec (GateAttr) – The gate to decompose, encapsulated as a SPEC.

Return type

float

Raises

CompilationError – If the provided gate on the provided labels cannot be decomposed.

class trueq.compilation.BestCostDecomposer(*strategies, cache_size=1024)

Decomposes gates by applying the DecompStrategy with the lowest cost.

Parameters
• *strategies – One or more DecompStrategy.

• cache_size (int) – The size of the cache used for storing GateAttrs.

apply(labels, op)

Decomposes the provided operation by applying the strategy with the lowest cost on the provided labels.

Returns the input operation if it is not a Gate.

Parameters
• labels (tuple) – The qubit labels on which op acts.

• op (Operation) – The circuit operation to decompose.

## AllocateLabels

class trueq.compilation.AllocateLabels(graph)

Relabels a Circuit to match the labels and topology of a Graph. When relabeling, it will choose new labels that maximize the the number of valid pairings and minimize the distance between qudit labels.

import trueq as tq
import trueq.visualization as tqv

graph = tqv.Graph.aspen_11(show_labels=True)
circ = tq.Circuit(
[
{(0, 1): tq.Gate.cx},
{(0, 2): tq.Gate.cx},
{(0, 3): tq.Gate.cx},
{(0, 4): tq.Gate.cx},
]
)

alloc = tq.compilation.AllocateLabels(graph)
circ = tq.compilation.Compiler([alloc]).compile(circ)
assert circ.key.relabeling == ((0, 1, 2, 3, 4), (26, 11, 25, 27, 10))
circ.draw()


Inspecting the returned circuit, we see that labels 0, 1, 2, 3, 4 of the input circuit got respectively mapped to labels 26, 11, 25, 27, 10, of the Aspen-11 chip. Thus the output circuit has three out of the four input circuits valid under the connectivity of this graph.

Note that labels of the target graph that are not assigned in the remapping are not included in key.relabeling.

Parameters

graph (trueq.visualization.Graph) – The graph that specifies the qudit layout for this circuit to be relabeled to match.

## 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.

import trueq as tq

# make a simple circuit with H gates on each qubit followed by measurements
circuit = tq.Circuit([{range(4): tq.Gate.h}])
circuit.measure_all()

# create a Compiler with a CompilePaulis pass and apply it to the circuit
compiler = tq.Compiler([tq.compilation.CompilePaulis()])
compiled_circ = compiler.compile(circuit)

print(compiled_circ.key)
compiled_circ

Key(compiled_pauli=Weyls('ZXZX'))

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: ZXZX Marker 0 Compilation tools may only recompile cycles with equal markers. (0): Gate.h Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: 'X': 127.279 'Z': 127.279 Matrix: 0.71 0.71 0.71 -0.71 (1): Gate.h Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: 'X': 127.279 'Z': 127.279 Matrix: 0.71 0.71 0.71 -0.71 (2): Gate.h Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: 'X': 127.279 'Z': 127.279 Matrix: 0.71 0.71 0.71 -0.71 (3): Gate.h Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: 'X': 127.279 'Z': 127.279 Matrix: 0.71 0.71 0.71 -0.71 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 (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 (3): Gate.x Name: Gate.x Aliases: Gate.x Gate.cliff1 Generators: 'X': 180.0 Matrix: 1.00 1.00 1 Marker 1 Compilation tools may only recompile cycles with equal markers. (0): Meas() Name: Meas() (1): Meas() Name: Meas() (2): Meas() Name: Meas() (3): Meas() Name: Meas()

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.

## 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.

## DeferredSwapper

class trueq.compilation.DeferredSwapper(graph)

Inserts swaps and decomposes gates of a Circuit to obey the connectivity of Graph.

import trueq as tq
import trueq.visualization as tqv

graph = tqv.Graph.aspen_11(show_labels=True)
circ = tq.Circuit([{(26, 10): tq.Gate.cx}, {(10, 26): tq.Gate.cz}])

swapper = tq.compilation.DeferredSwapper(graph)
tq.compilation.Compiler([swapper]).compile(circ).draw()

Parameters

graph (trueq.visualization.Graph) – The graph that specifies the qudit layout that this circuit must obey.

## 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: 'ZX': -90.0 'IX': 90.0 'ZI': 90.0 Matrix: 1.00 1.00 1.00 1.00 (2, 3): cx() Name: cx() Aliases: Gate.cx Gate.cnot Likeness: CNOT Generators: 'ZX': -90.0 'IX': 90.0 'ZI': 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()

compiler = tq.Compiler([tq.compilation.Justify()])

compiler.compile(circuit).draw()


## MarkBlocks

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

Pass that marks cycles which contain multi-qubit gates if none of the existing non-measurement cycles in the circuit have been marked with non-zero values. This pass is similar to MarkCycles, except that it uses the same marker for any adjacent cycles that are not separated by single-qubit cycles. By default, markers start at a value one greater than the largest existing marker value, and increment up for every additional block of subsequent cycles containing multi-qubit gates.

import trueq as tq

# make a simple circuit with two single-qubit gates between blocks of
# two-qubit gates
circuit = tq.Circuit(
[
{0: tq.Gate.h},
{(0, 1): tq.Gate.cx},
{(0, 2): tq.Gate.cz},
{1: tq.Gate.h},
{(0, 1): tq.Gate.cx},
{(1, 2): tq.Gate.cz},
]
)

compiler = tq.Compiler([tq.compilation.MarkBlocks()])

# the first block of two-qubit gate cycles will be marked with "1" and the
# second block with "2"
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): Gate.h Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: 'X': 127.279 'Z': 127.279 Matrix: 0.71 0.71 0.71 -0.71 1 Marker 1 Compilation tools may only recompile cycles with equal markers. (0, 1): Gate.cx Name: Gate.cx Aliases: Gate.cx Gate.cnot Likeness: CNOT Generators: 'ZX': -90.0 'IX': 90.0 'ZI': 90.0 Matrix: 1.00 1.00 1.00 1.00 1 Marker 1 Compilation tools may only recompile cycles with equal markers. (0, 2): Gate.cz Name: Gate.cz Aliases: Gate.cz Likeness: CNOT Generators: 'ZZ': -90.0 'ZI': 90.0 'IZ': 90.0 Matrix: 1.00 1.00 1.00 -1.00 Marker 0 Compilation tools may only recompile cycles with equal markers. (1): Gate.h Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: 'X': 127.279 'Z': 127.279 Matrix: 0.71 0.71 0.71 -0.71 2 Marker 2 Compilation tools may only recompile cycles with equal markers. (0, 1): Gate.cx Name: Gate.cx Aliases: Gate.cx Gate.cnot Likeness: CNOT Generators: 'ZX': -90.0 'IX': 90.0 'ZI': 90.0 Matrix: 1.00 1.00 1.00 1.00 2 Marker 2 Compilation tools may only recompile cycles with equal markers. (1, 2): Gate.cz Name: Gate.cz Aliases: Gate.cz Likeness: CNOT Generators: 'ZZ': -90.0 'ZI': 90.0 'IZ': 90.0 Matrix: 1.00 1.00 1.00 -1.00
Parameters

marker (int | NoneType) – The marker value added to hard cycles. The default value None causes the first block to have marker one greater than the largest marker already present in the circuit, and subsequent blocks to have markers incremented by 1 for each block found.

## 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 start at 1 and increment up for every cycle containing a multi-qubit gate found.

import trueq as tq

# make a simple circuit with a single-qubit and two two-qubit gates
circuit = tq.Circuit(
[{0: tq.Gate.h}, {(0, 1): tq.Gate.cx}, {(0, 2): tq.Gate.cz}]
)

compiler = tq.Compiler([tq.compilation.MarkCycles()])

# the two-qubit gate cycles will be marked with "1" and "2"
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): Gate.h Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: 'X': 127.279 'Z': 127.279 Matrix: 0.71 0.71 0.71 -0.71 1 Marker 1 Compilation tools may only recompile cycles with equal markers. (0, 1): Gate.cx Name: Gate.cx Aliases: Gate.cx Gate.cnot Likeness: CNOT Generators: 'ZX': -90.0 'IX': 90.0 'ZI': 90.0 Matrix: 1.00 1.00 1.00 1.00 2 Marker 2 Compilation tools may only recompile cycles with equal markers. (0, 2): Gate.cz Name: Gate.cz Aliases: Gate.cz Likeness: CNOT Generators: 'ZZ': -90.0 'ZI': 90.0 'IZ': 90.0 Matrix: 1.00 1.00 1.00 -1.00
# in circuits that already have at least one cycle marked, the MarkCycles pass
# does nothing
circuit = tq.Circuit(
[
{0: tq.Gate.h},
tq.Cycle({(0, 1): tq.Gate.cx}, marker=1),
{(0, 2): tq.Gate.cz},
]
)

compiler = tq.Compiler([tq.compilation.MarkCycles(marker=2)])

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): Gate.h Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: 'X': 127.279 'Z': 127.279 Matrix: 0.71 0.71 0.71 -0.71 1 Marker 1 Compilation tools may only recompile cycles with equal markers. (0, 1): Gate.cx Name: Gate.cx Aliases: Gate.cx Gate.cnot Likeness: CNOT Generators: 'ZX': -90.0 'IX': 90.0 'ZI': 90.0 Matrix: 1.00 1.00 1.00 1.00 Marker 0 Compilation tools may only recompile cycles with equal markers. (0, 2): Gate.cz Name: Gate.cz Aliases: Gate.cz Likeness: CNOT Generators: 'ZZ': -90.0 'ZI': 90.0 'IZ': 90.0 Matrix: 1.00 1.00 1.00 -1.00
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(max_sys=1, marker=None, **_)

Pass that takes a list of cycles, finds compatabile labels and gates, and 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 merging results in a two-qubit gate that is the Kronecker product of two single-qubit gates, then it will be broken apart into the two-single qubit gates.

This class will only merge gates if adjacent cycles have the same marker.

import trueq as tq

# make a circuit containing 4 X gates in a row, and merge them together
circuit = tq.Circuit([{0: tq.Gate.x}] * 4)

compiler = tq.Compiler([tq.compilation.Merge()])

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): Gate.id Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Likeness: Identity Generators: 'I': 0 Matrix: 1.00 1.00
Parameters
• max_sys (int) – The maximum number of labels to merge at any given time. If only single qubit merging is desired, then set max_sys=1, and so on.

• 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.

## 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.

import trueq as tq
from trueq.config import GateFactory

# create a circuit with a single H gate
circuit = tq.Circuit({0: tq.Gate.h})

# Define GateFactory objects for an X and Z rotation
rx = GateFactory.from_hamiltonian("RX", [["X", "theta"]], parameters=["theta"])
rz = GateFactory.from_hamiltonian("RZ", [["Z", "phi"]], parameters=["phi"])

# the following Native1Q pass will decompose this circuit into X and Z gates
#  using the ZXZ decomposition
compiler = tq.Compiler(
[tq.compilation.Native1Q(factories=[rx, rz], mode="ZXZ")]
)

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): RZ(phi) Name: RZ(phi) Aliases: Gate.s Gate.sz Gate.cliff9 Parameters: phi = 90.0 Generators: 'Z': 90.0 Matrix: 0.71 -0.71j 0.71 0.71j Marker 0 Compilation tools may only recompile cycles with equal markers. (0): RX(theta) Name: RX(theta) Aliases: Gate.sx Gate.cliff5 Parameters: theta = 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): RZ(phi) Name: RZ(phi) Aliases: Gate.s Gate.sz Gate.cliff9 Parameters: phi = 90.0 Generators: 'Z': 90.0 Matrix: 0.71 -0.71j 0.71 0.71j

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

## 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 an R gate and a Z gate. A GateFactory for R can be found in r_factory.

import trueq as tq
from trueq.config import GateFactory

# define GateFactories for the R and Z gates
r = GateFactory.from_hamiltonian(
"R", [["Z", "-theta"], ["X", 90], ["Z", "theta"]], parameters=["theta"]
)
rz = GateFactory.from_hamiltonian("RZ", [["Z", "phi"]], parameters=["phi"])

native1qrrz = tq.compilation.Native1QRRZ(factories=[r, rz])

native1qrrz.apply((0,), tq.Gate.x)

[{(0,): R(theta)}, {(0,): R(theta)}, {(0,): RZ(phi)}]

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.

import trueq as tq
from trueq.config import GateFactory

# define GateFactorys for the X and Z gates
x90 = GateFactory.from_hamiltonian("X90", [["X", 90]])
rz = GateFactory.from_hamiltonian("RZ", [["Z", "phi"]], parameters=["phi"])

native1qmode = tq.compilation.Native1QMode(factories=[x90, rz])

native1qmode.apply((0,), tq.Gate.h)

[{(0,): RZ(phi)},
{(0,): X90()},
{(0,): RZ(phi)},
{(0,): X90()},
{(0,): RZ(phi)}]

Parameters

## 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.

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:

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.

import trueq as tq
from trueq.config import GateFactory

# Create a circuit with a single random SU(4) gate
circuit = tq.Circuit({(0, 1): tq.Gate.random(4)})

# define a GateFactory for the CZ gate
cz = GateFactory.from_matrix("CZ", tq.Gate.cz.mat)

compiler = tq.Compiler([tq.compilation.Native2Q(factories=[cz])])

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): Gate(Y, X, ...) Name: Gate(Y, X, ...) Generators: 'Y': 11.101 'X': -77.99 'Z': 12.286 Matrix: -0.40 0.66j -0.44 -0.46j -0.55 -0.32j -0.55 0.54j (1): Gate(Y, X, ...) Name: Gate(Y, X, ...) Generators: 'Y': -7.552 'X': -61.126 'Z': 63.19 Matrix: 0.84 0.25j -0.34 0.35j -0.41 0.25j 0.06 0.87j Marker 0 Compilation tools may only recompile cycles with equal markers. (0, 1): CZ() Name: CZ() Aliases: Gate.cz Likeness: CNOT Generators: 'ZZ': -90.0 'ZI': 90.0 'IZ': 90.0 Matrix: 1.00 1.00 1.00 -1.00 Marker 0 Compilation tools may only recompile cycles with equal markers. (0): Gate(Y, X, ...) Name: Gate(Y, X, ...) Generators: 'Y': -7.757 'X': 89.757 'Z': -7.757 Matrix: 0.46 0.54j 0.54 -0.46j 0.46 -0.54j 0.54 0.46j (1): Gate(Y) Name: Gate(Y) Generators: 'Y': -5.578 Matrix: 0.71 -0.71j 0.03 -0.03j -0.03 0.03j 0.71 -0.71j Marker 0 Compilation tools may only recompile cycles with equal markers. (0, 1): CZ() Name: CZ() Aliases: Gate.cz Likeness: CNOT Generators: 'ZZ': -90.0 'ZI': 90.0 'IZ': 90.0 Matrix: 1.00 1.00 1.00 -1.00 Marker 0 Compilation tools may only recompile cycles with equal markers. (0): Gate.cliff14 Name: Gate.cliff14 Aliases: Gate.cliff14 Generators: 'Y': -127.279 'Z': -127.279 Matrix: -0.50 0.50j 0.50 0.50j -0.50 -0.50j 0.50 -0.50j (1): Gate(Y) Name: Gate(Y) Generators: 'Y': -60.75 Matrix: 0.61 -0.61j 0.36 -0.36j -0.36 0.36j 0.61 -0.61j Marker 0 Compilation tools may only recompile cycles with equal markers. (0, 1): CZ() Name: CZ() Aliases: Gate.cz Likeness: CNOT Generators: 'ZZ': -90.0 'ZI': 90.0 'IZ': 90.0 Matrix: 1.00 1.00 1.00 -1.00 Marker 0 Compilation tools may only recompile cycles with equal markers. (0): Gate(Y, X, ...) Name: Gate(Y, X, ...) Generators: 'Y': 148.474 'X': -95.73 'Z': -153.458 Matrix: -0.74 -0.06j -0.61 -0.27j 0.00 0.67j 0.24 -0.70j (1): Gate(Y, X, ...) Name: Gate(Y, X, ...) Generators: 'Y': 50.306 'X': 58.758 'Z': 46.787 Matrix: 0.79 0.08j -0.08 -0.60j 0.58 -0.17j 0.39 0.69j
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)

An OperationReplacement which checks if the specified gate can be generated directly from a single output of a single factory present in the GateFactory list with an appropriate choice of parameter values, and if so, replaces a Gate with the NativeGate.

For example, suppose we have a factory list [rz(phi), u3(phi, theta, lambda), x90()] and encounter a Gate.rx(90) gate. The first operation, rz(phi), will be skipped because it can’t make an $X90$ for any value of phi, but the u3(phi, theta, lambda) factory will be used because it is next in line and it can make any single qubit gate including an $X90$. The actual x90() in the factory list will be ignored (even though it is an exact match) because it comes last in the factory list.

import trueq as tq
from trueq.config import GateFactory

rz = GateFactory.from_hamiltonian("RZ", [["Z", "phi"]], parameters=["phi"])
u3 = tq.config.u3_factory
x90 = GateFactory.from_hamiltonian("X90", [["X", 90]])

native_exact = tq.compilation.NativeExact(factories=[rz, u3, x90])

native_exact.apply((0,), tq.Gate.rx(90))

[{(0,): U3Gate(theta, phi, ...)}]

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.

## OneQuditDecomp

class trueq.compilation.OneQuditDecomp(factories, optimal=False, **_)

A pass which decomposes cycles of arbitrary single-qudit gates into alternations of cycles of native gates with diagonal gates. See native_cycles() for details on the form of the cycles of native gates.

The native gates are generated by the given factories. These factories should produce gates that perform subspace rotations between adjacent energy levels (i.e. computation basis states). For example, a qubit only has two levels so any factory that produces non-diagonal gates will suffice. For a qutrit, two factories are required: one between $|0\rangle\leftrightarrow|1\rangle$ and one between $|0\rangle\leftrightarrow|2\rangle$. If a given qubit label has a choice between applicable factories, the one with fewer free parameters is preferred.

Any non single-qudit gates found in a provided cycle are placed into a new cycle at the end of the decomposition.

Note

This compiler pass is an independent alternative to Native1Q and its partners. However, it works for qubits and qudits.

In the first example, we show how this class can be easily used to decompose rounds of single qubit gates. The same $\sqrt{X}$ factory is used for every qubit.

import trueq as tq

# Compiler.basic will use the factories z-rotation and RX(90) by default
compiler = tq.Compiler.basic(passes=(tq.compilation.OneQuditDecomp,))

# we decompose all single qubit gates in the circuit with guaranteed alignment
circuits = tq.make_cb({(0, 1): tq.Gate.cnot}, [2])
compiler.compile(circuits[0])

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: analyze_decays: YY_YX_XY_XX_YZ_YI_XZ_XI_ZY_ZX_IY_IX_ZZ_ZI_IZ_II compiled_pauli: XI cycles: (Cycle((0, 1): Gate.cx),) measurement_basis: YY n_random_cycles: 2 protocol: CB twirl: Paulis on [0, 1] Marker 0 Compilation tools may only recompile cycles with equal markers. (0): Gate.cliff8 Name: Gate.cliff8 Aliases: Gate.cliff8 Generators: 'Z': -90.0 Matrix: 0.71 0.71j 0.71 -0.71j (1): Gate.cliff8 Name: Gate.cliff8 Aliases: Gate.cliff8 Generators: 'Z': -90.0 Matrix: 0.71 0.71j 0.71 -0.71j Marker 0 Compilation tools may only recompile cycles with equal markers. (0): sx() Name: sx() Aliases: Gate.sx Gate.cliff5 Generators: 'X': 90.0 Matrix: 0.71 -0.71j -0.71j 0.71 (1): sx() Name: sx() Aliases: Gate.sx Gate.cliff5 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): Gate.s Name: Gate.s Aliases: Gate.s Gate.sz Gate.cliff9 Generators: 'Z': 90.0 Matrix: 0.71 -0.71j 0.71 0.71j (1): Gate.s Name: Gate.s Aliases: Gate.s Gate.sz Gate.cliff9 Generators: 'Z': 90.0 Matrix: 0.71 -0.71j 0.71 0.71j Marker 0 Compilation tools may only recompile cycles with equal markers. (0): sx() Name: sx() Aliases: Gate.sx Gate.cliff5 Generators: 'X': 90.0 Matrix: 0.71 -0.71j -0.71j 0.71 (1): sx() Name: sx() Aliases: Gate.sx Gate.cliff5 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): Gate.cliff8 Name: Gate.cliff8 Aliases: Gate.cliff8 Generators: 'Z': -90.0 Matrix: 0.71 0.71j 0.71 -0.71j (1): Gate.cliff8 Name: Gate.cliff8 Aliases: Gate.cliff8 Generators: 'Z': -90.0 Matrix: 0.71 0.71j 0.71 -0.71j 1 Marker 1 Compilation tools may only recompile cycles with equal markers. (0, 1): Gate.cx Name: Gate.cx Aliases: Gate.cx Gate.cnot Likeness: CNOT Generators: 'ZX': -90.0 'IX': 90.0 'ZI': 90.0 Matrix: 1.00 1.00 1.00 1.00 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.00j 1.00j (1): Gate.z Name: Gate.z Aliases: Gate.z Gate.cliff3 Generators: 'Z': -180.0 Matrix: 1.00j -1.00j Marker 0 Compilation tools may only recompile cycles with equal markers. (0): sx() Name: sx() Aliases: Gate.sx Gate.cliff5 Generators: 'X': 90.0 Matrix: 0.71 -0.71j -0.71j 0.71 (1): sx() Name: sx() Aliases: Gate.sx Gate.cliff5 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): Gate.z Name: Gate.z Aliases: Gate.z Gate.cliff3 Generators: 'Z': -180.0 Matrix: 1.00j -1.00j (1): Gate.z Name: Gate.z Aliases: Gate.z Gate.cliff3 Generators: 'Z': -180.0 Matrix: 1.00j -1.00j Marker 0 Compilation tools may only recompile cycles with equal markers. (0): sx() Name: sx() Aliases: Gate.sx Gate.cliff5 Generators: 'X': 90.0 Matrix: 0.71 -0.71j -0.71j 0.71 (1): sx() Name: sx() Aliases: Gate.sx Gate.cliff5 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): Gate.id Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Likeness: Identity Generators: 'I': 0 Matrix: 1.00j 1.00j (1): Gate.id Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Likeness: Identity Generators: 'I': 0 Matrix: 1.00j 1.00j 2 Marker 2 Compilation tools may only recompile cycles with equal markers. (0, 1): Gate.cx Name: Gate.cx Aliases: Gate.cx Gate.cnot Likeness: CNOT Generators: 'ZX': -90.0 'IX': 90.0 'ZI': 90.0 Matrix: 1.00 1.00 1.00 1.00 Marker 0 Compilation tools may only recompile cycles with equal markers. (0): Gate.s Name: Gate.s Aliases: Gate.s Gate.sz Gate.cliff9 Generators: 'Z': -270.0 Matrix: -0.71 0.71j -0.71 -0.71j (1): Gate.s Name: Gate.s Aliases: Gate.s Gate.sz Gate.cliff9 Generators: 'Z': -270.0 Matrix: -0.71 0.71j -0.71 -0.71j Marker 0 Compilation tools may only recompile cycles with equal markers. (0): sx() Name: sx() Aliases: Gate.sx Gate.cliff5 Generators: 'X': 90.0 Matrix: 0.71 -0.71j -0.71j 0.71 (1): sx() Name: sx() Aliases: Gate.sx Gate.cliff5 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): Gate.s Name: Gate.s Aliases: Gate.s Gate.sz Gate.cliff9 Generators: 'Z': -270.0 Matrix: -0.71 0.71j -0.71 -0.71j (1): Gate.s Name: Gate.s Aliases: Gate.s Gate.sz Gate.cliff9 Generators: 'Z': -270.0 Matrix: -0.71 0.71j -0.71 -0.71j Marker 0 Compilation tools may only recompile cycles with equal markers. (0): sx() Name: sx() Aliases: Gate.sx Gate.cliff5 Generators: 'X': 90.0 Matrix: 0.71 -0.71j -0.71j 0.71 (1): sx() Name: sx() Aliases: Gate.sx Gate.cliff5 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): Gate.cliff8 Name: Gate.cliff8 Aliases: Gate.cliff8 Generators: 'Z': -90.0 Matrix: 0.71 0.71j 0.71 -0.71j (1): Gate.s Name: Gate.s Aliases: Gate.s Gate.sz Gate.cliff9 Generators: 'Z': -270.0 Matrix: -0.71 0.71j -0.71 -0.71j 3 Marker 3 Compilation tools may only recompile cycles with equal markers. (0): Meas() Name: Meas() (1): Meas() Name: Meas()

In the second example, we show a qutrit configuration where each subsystem is assigned fixed rotation values on each subspace.

import trueq as tq
import numpy as np

# define two factories, one for each subspace, with angles in degrees
a = np.pi / 360
fn1 = lambda theta: [
[np.cos(a * theta), -1j * np.sin(a * theta), 0],
[-1j * np.sin(a * theta), np.cos(a * theta), 0],
[0, 0, 1],
]
f1 = tq.config.GateFactory.from_function("f1", fn1, dim=3)

fn2 = lambda theta: [
[1, 0, 0],
[0, np.cos(a * theta), -1j * np.sin(a * theta)],
[0, -1j * np.sin(a * theta), np.cos(a * theta)],
]
f2 = tq.config.GateFactory.from_function("f2", fn2, dim=3)

# define specific values on certain subsystems
f1_params = {0: [68], 1: [94], 2: [71], 3: [86], 4: [90]}
f2_params = {0: [65], 1: [94], 2: [-75], 3: [62], 4: [90]}

# helper function that returns new factories where free parameters become fixed,
# and where it is only allowed to act on one particular label
def fixed_factory(factory, label, args):
params = {name: val for name, val in zip(factory.free_parameters, args)}
return factory.fix_parameters({(label,): ()}, **params)

# enter all of the factories into a list. note that we are adding both the
# parameterized and fixed factories. this is for demonstration purposes, you
# can just enter the fixed or the parametric, as needed. in this case, the
# parametric ones will be used as backup if no fixed factory acts on a label
# required by a cycle to decompose
factories = [f1, f2]
factories.extend(fixed_factory(f1, i, args) for i, args in f1_params.items())
factories.extend(fixed_factory(f2, i, args) for i, args in f2_params.items())

# instantiate compiler with only this pass
compiler = tq.Compiler([tq.compilation.OneQuditDecomp(factories)])

# make a random cycle on three qutrits and decompose it
circuit = tq.Circuit([{label: tq.Gate.random(3) for label in [0, 2, 8]}])
compiler.compile(circuit[0])

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() Name: Gate() Matrix: 0.14 -0.99j -0.98 0.17j -0.85 0.53j (2): Gate() Name: Gate() Matrix: 0.49 -0.87j -0.47 0.88j 0.37 -0.93j (8): Gate() Name: Gate() Matrix: -0.86 0.51j -0.02 -1.00j -1.00 0.03j Marker 0 Compilation tools may only recompile cycles with equal markers. (0): f2(theta) Name: f2(theta) Parameters: theta = 65.0 Matrix: 1.00 0.84 -0.54j -0.54j 0.84 (2): f2(theta) Name: f2(theta) Parameters: theta = -75.0 Matrix: 1.00 0.79 0.61j 0.61j 0.79 (8): f2(theta) Name: f2(theta) Parameters: theta = 90.0 Matrix: 1.00 0.71 -0.71j -0.71j 0.71 Marker 0 Compilation tools may only recompile cycles with equal markers. (0): Gate() Name: Gate() Matrix: 1.00 0.05 -1.00j 0.05 1.00j (2): Gate() Name: Gate() Matrix: 1.00 0.22 -0.97j 0.22 0.97j (8): Gate() Name: Gate() Matrix: 1.00 0.16 -0.99j 0.16 0.99j Marker 0 Compilation tools may only recompile cycles with equal markers. (0): f2(theta) Name: f2(theta) Parameters: theta = 65.0 Matrix: 1.00 0.84 -0.54j -0.54j 0.84 (2): f2(theta) Name: f2(theta) Parameters: theta = -75.0 Matrix: 1.00 0.79 0.61j 0.61j 0.79 (8): f2(theta) Name: f2(theta) Parameters: theta = 90.0 Matrix: 1.00 0.71 -0.71j -0.71j 0.71 Marker 0 Compilation tools may only recompile cycles with equal markers. (0): Gate() Name: Gate() Matrix: 1.00 0.71 0.70j 0.71 -0.70j (2): Gate() Name: Gate() Matrix: 1.00 0.73 0.69j 0.73 -0.69j (8): Gate() Name: Gate() Matrix: 1.00 0.71 0.71j 0.71 -0.71j Marker 0 Compilation tools may only recompile cycles with equal markers. (0): f2(theta) Name: f2(theta) Parameters: theta = 65.0 Matrix: 1.00 0.84 -0.54j -0.54j 0.84 (2): f2(theta) Name: f2(theta) Parameters: theta = -75.0 Matrix: 1.00 0.79 0.61j 0.61j 0.79 (8): f2(theta) Name: f2(theta) Parameters: theta = 90.0 Matrix: 1.00 0.71 -0.71j -0.71j 0.71 Marker 0 Compilation tools may only recompile cycles with equal markers. (0): Gate() Name: Gate() Matrix: 1.00 0.90 0.43j 0.90 -0.43j (2): Gate() Name: Gate() Matrix: 1.00 0.47 0.88j 0.47 -0.88j (8): Gate() Name: Gate() Matrix: 1.00 -0.41 -0.91j -0.41 0.91j Marker 0 Compilation tools may only recompile cycles with equal markers. (0): f1(theta) Name: f1(theta) Parameters: theta = 68.0 Matrix: 0.83 -0.56j -0.56j 0.83 1.00 (2): f1(theta) Name: f1(theta) Parameters: theta = 71.0 Matrix: 0.81 -0.58j -0.58j 0.81 1.00 (8): f1(theta) Name: f1(theta) Parameters: theta = 90.0 Matrix: 0.71 -0.71j -0.71j 0.71 1.00 Marker 0 Compilation tools may only recompile cycles with equal markers. (0): Gate() Name: Gate() Matrix: 0.33 -0.94j 0.33 0.94j 1.00 (2): Gate() Name: Gate() Matrix: 0.11 -0.99j 0.11 0.99j 1.00 (8): Gate() Name: Gate() Matrix: 0.22 -0.98j 0.22 0.98j 1.00 Marker 0 Compilation tools may only recompile cycles with equal markers. (0): f1(theta) Name: f1(theta) Parameters: theta = 68.0 Matrix: 0.83 -0.56j -0.56j 0.83 1.00 (2): f1(theta) Name: f1(theta) Parameters: theta = 71.0 Matrix: 0.81 -0.58j -0.58j 0.81 1.00 (8): f1(theta) Name: f1(theta) Parameters: theta = 90.0 Matrix: 0.71 -0.71j -0.71j 0.71 1.00 Marker 0 Compilation tools may only recompile cycles with equal markers. (0): Gate() Name: Gate() Matrix: 0.75 0.66j 0.75 -0.66j 1.00 (2): Gate() Name: Gate() Matrix: 0.72 0.69j 0.72 -0.69j 1.00 (8): Gate() Name: Gate() Matrix: 0.71 0.71j 0.71 -0.71j 1.00 Marker 0 Compilation tools may only recompile cycles with equal markers. (0): f1(theta) Name: f1(theta) Parameters: theta = 68.0 Matrix: 0.83 -0.56j -0.56j 0.83 1.00 (2): f1(theta) Name: f1(theta) Parameters: theta = 71.0 Matrix: 0.81 -0.58j