pytket.transform#

class pytket.transform.PauliSynthStrat#

Enum for available strategies to synthesise Pauli gadgets

Members:

Individual : Synthesise gadgets individually

Pairwise : Synthesise gadgets using an efficient pairwise strategy from Cowtan et al (https://arxiv.org/abs/1906.01734)

Sets : Synthesise gadgets in commuting sets

__init__(self: pytket.transform.PauliSynthStrat, value: int) None#
property name#
class pytket.transform.Transform#

An in-place transformation of a Circuit.

static CnXPairwiseDecomposition() pytket.transform.Transform#

Decompose CnX gates to 2-qubit gates and single qubit gates. For every two CnX gates, reorder their control qubits to improve the chance of gate cancellation.

static CommuteSQThroughSWAP(*args, **kwargs)#

Overloaded function.

  1. CommuteSQThroughSWAP(avg_node_errors: dict[pytket.unit_id.Node, float]) -> pytket.transform.Transform

Commutes single qubit gates through SWAP gates, leaving them on the physical qubit with best fidelity for given gate type. Assumes the circuit is already mapped onto the architecture.

Parameters:

avg_node_errors – a dict mapping Nodes to average single-qubit gate errors

  1. CommuteSQThroughSWAP(op_node_errors: dict[pytket.unit_id.Node, dict[pytket.circuit.OpType, float]]) -> pytket.transform.Transform

Commutes single qubit gates through SWAP gates, leaving them on the physical qubit with best fidelity for given gate type. Assumes the circuit is already mapped onto the architecture.

Parameters:

avg_node_errors – a dict of dicts, mapping Nodes to dicts of OpType to single-qubit gate error maps

static CommuteThroughMultis() pytket.transform.Transform#

Applies a collection of commutation rules to move single qubit operations past multiqubit operations they commute with, towards the front of the circuit.

static DecomposeBRIDGE() pytket.transform.Transform#

Decomposes all BRIDGE gates into CX gates.

static DecomposeBoxes(excluded_types: set[pytket.circuit.OpType] = set(), excluded_opgroups: set[str] = set()) pytket.transform.Transform#

Recursively replaces all boxes by their decomposition into circuits.

Parameters:
  • excluded_types – box `OpType`s excluded from decomposition

  • excluded_opgroups – opgroups excluded from decomposition

static DecomposeCCX() pytket.transform.Transform#

Decomposes all 3-qubit Toffoli (CCX) gates into Clifford+T gates.

static DecomposeCXDirected(arc: pytket.architecture.Architecture) pytket.transform.Transform#

Decompose CX gates to H+CX to match the direction of the CXs to edges of the Architecture arc. Assumes the circuit already satisfies the connectivity of arc.

Parameters:

arc – The architecture for which CXs should be redirected

static DecomposeControlledRys() pytket.transform.Transform#

Decomposes all arbitrarily-quantum-controlled Rys into CX and Ry gates.

static DecomposeNPhasedX() pytket.transform.Transform#

Decompose NPhasedX gates into single-qubit PhasedX gates.

static DecomposeSWAP(circuit: pytket.circuit.Circuit) pytket.transform.Transform#

Decomposes all SWAP gates to provided replacement circuit.

Parameters:

circuit – A circuit that is logically equivalent to a SWAP operation

static DecomposeSWAPtoCX(arc: pytket.architecture.Architecture) pytket.transform.Transform#

Decomposes all SWAP gates into triples of CX gates. If the SWAP is adjacent to a CX, it will prefer to insert in the direction that allows for gate cancellation. If an Architecture is provided, this will prefer to insert the CXs such that fewer need redirecting.

Parameters:

arc – Device architecture used to specify a preference for CX direction

static DecomposeTK2(allow_swaps: bool = True, **kwargs) pytket.transform.Transform#

Decompose each TK2 gate into two-qubit gates.

We currently support CX, ZZMax and ZZPhase.

If one or more gate fidelities are provided, the two-qubit gate type achieving the highest fidelity will be chosen for the decomposition, as measured using squared trace fidelity. If no fidelities are provided, the TK2 gates will be decomposed exactly using CX gates. For equal fidelities, ZZPhase will be prefered over ZZMax and CX if the decomposition results in fewer two-qubit gates.

All TK2 gate parameters must be normalised, i.e. they must satisfy NormalisedTK2Predicate.

Gate fidelities are passed as keyword arguments to perform noise-aware decompositions. We currently support CX_fidelity, ZZMax_fidelity and ZZPhase_fidelity. If provided, the CX and ZZMax fidelities must be given by a single floating point fidelity. The ZZPhase fidelity is given as a lambda float -> float, mapping a ZZPhase angle parameter to its fidelity. These parameters will be used to return the optimal decomposition of each TK2 gate, taking noise into consideration.

Using the allow_swaps=True (default) option, qubits will be swapped when convenient to reduce the two-qubit gate count of the decomposed TK2.

If the TK2 angles are symbolic values, the decomposition will be exact (i.e. not noise-aware). It is not possible in general to obtain optimal decompositions for arbitrary symbolic parameters, so consider substituting for concrete values if possible.

Parameters:

allow_swaps – Whether to allow implicit wire swaps.

static GlobalisePhasedX(squash: bool = True) pytket.transform.Transform#

Turns all PhasedX and NPhasedX gates into global gates

Replaces any PhasedX gates with global NPhasedX gates. By default, this transform will squash all single-qubit gates to PhasedX and Rz gates before proceeding further. Existing non-global NPhasedX will not be preserved. This is the recommended setting for best performance. If squashing is disabled, each non-global PhasedX gate will be replaced with two global NPhasedX, but any other gates will be left untouched.

Parameters:

squash – Whether to squash the circuit in pre-processing (default: true).

If squash=true (default), the GlobalisePhasedX transform’s apply method will always return true. For squash=false, apply() will return true if the circuit was changed and false otherwise.

It is not recommended to use this transformation with symbolic expressions, as in certain cases a blow-up in symbolic expression sizes may occur.

static KAKDecomposition(*args, **kwargs)#

Overloaded function.

  1. KAKDecomposition(target_2qb_gate: pytket.circuit.OpType = <OpType.CX: 45>, cx_fidelity: float = 1.0, allow_swaps: bool = True) -> pytket.transform.Transform

Squash sequences of two-qubit operations into minimal form.

Squash together sequences of single- and two-qubit gates into minimal form. Can decompose to TK2 or CX gates.

Two-qubit operations can always be expressed in a minimal form of maximum three CXs, or as a single TK2 gate (a result also known as the KAK or Cartan decomposition).

It is in general recommended to squash to TK2 gates, and to then use the DecomposeTK2 pass for noise-aware decompositions to other gatesets. For backward compatibility, decompositions to CX are also supported. In this case, cx_fidelity can be provided to perform approximate decompositions to CX gates.

When decomposing to TK2 gates, any sequence of two or more two-qubit gates on the same set of qubits is replaced by a single TK2 gate. When decomposing to CX, the substitution is only performed if it results in a reduction of the number of CX gates, or if at least one of the two-qubit passes is not a CX.

Using the allow_swaps=True (default) option, qubits will be swapped when convenient to further reduce the two-qubit gate count. (only applicable when decomposing to CX gates).

Parameters:
  • target_2qb_gate – OpType to decompose to. Either TK2 or CX.

  • cx_fidelity – Estimated CX gate fidelity, used when target_2qb_gate=CX.

  • allow_swaps – Whether to allow implicit wire swaps.

  1. KAKDecomposition(cx_fidelity: float) -> pytket.transform.Transform

static NormaliseTK2() pytket.transform.Transform#

Normalises all TK2 gates.

TK2 gates have three angles in the interval [0, 4], but these can always be normalised to be within the so-called Weyl chamber by adding single-qubit gates.

More precisely, the three angles a, b, c of TK2(a, b, c) are normalised exactly when the two following conditions are met:
  • numerical values must be in the Weyl chamber, ie 1/2 >= a >= b >= |c|,

  • symbolic values must come before any numerical value in the array.

After this transform, all TK2 angles will be normalised and the circuit will satisfy NormalisedTK2Predicate.

static OptimiseCliffords(allow_swaps: bool = True) pytket.transform.Transform#

An optimisation pass that performs a number of rewrite rules for simplifying Clifford gate sequences, similar to Duncan & Fagan (https://arxiv.org/abs/1901.10114). Given a circuit with CXs and any single-qubit gates, produces a circuit with Z, X, S, V, U1, U2, U3, CX gates. This will not preserve CX placement or orientation and may introduce implicit wire swaps.

Parameters:

allow_swaps – dictates whether the rewriting will disregard CX placement or orientation and introduce wire swaps.

static OptimisePauliGadgets(cx_config: pytket.circuit.CXConfigType = CXConfigType.Snake) pytket.transform.Transform#

An optimisation pass that identifies the Pauli gadgets corresponding to any non-Clifford rotations and synthesises them pairwise (see Cowtan, Duncan, Dilkes, Simmons, & Sivarajah https://arxiv.org/abs/1906.01734). Results use TK1, CX gates.

static OptimisePhaseGadgets(cx_config: pytket.circuit.CXConfigType = CXConfigType.Snake) pytket.transform.Transform#

An optimisation pass that starts by identifying subcircuits corresponding to phase gadgets (see Cowtan, Duncan, Dilkes, Simmons, & Sivarajah https://arxiv.org/abs/1906.01734) and resynthesises them in a balanced-tree form, followed by applying OptimisePostRouting. Results use TK1 and CX gates. This will not preserve CX placement or orientation.

static OptimisePostRouting() pytket.transform.Transform#

Fast optimisation pass, performing basic simplifications. Works on any circuit, giving the result in TK1 and CX gates. If all multi-qubit gates are CXs, then this preserves their placement and orientation, so it is safe to perform after routing.

static OptimiseStandard() pytket.transform.Transform#

Fast optimisation pass, performing basic simplifications. Works on any circuit, giving the result in TK1 and TK2 gates. Preserves connectivity of circuit.

static PushCliffordsThroughMeasures() pytket.transform.Transform#

Derives a new set of end-of-Circuit measurement operators by acting on end-of-Circuit measurements with a Clifford subcircuit. The new set of measurement operators is necessarily commuting and is implemented by adding a new mutual diagonalisation Clifford subcirciuit to the end of the Circuit and implementing the remaining diagonal measurement operators by measuring and permuting the output.

static RebaseToCirq() pytket.transform.Transform#

Rebase from any gate set into PhasedX, Rz, CZ.

static RebaseToCliffordSingles() pytket.transform.Transform#

Replace all single-qubit unitary gates outside the set {Z, X, S, V} that are recognized as Clifford operations with an equivalent sequence of gates from that set.

static RebaseToProjectQ() pytket.transform.Transform#

Rebase from any gate set into the gate set supported by ProjectQ (Rx, Ry, Rz, X, Y, Z, S, T, V, H, CX, CZ, CRz, SWAP).

static RebaseToPyZX() pytket.transform.Transform#

Rebase from any gate set into the gate set supported by PyZX (Rx, Rz, X, Z, S, T, H, CX, CZ, SWAP).

static RebaseToQuil() pytket.transform.Transform#

Rebase from any gate set into Rx, Rz, CZ.

static RebaseToRzRx() pytket.transform.Transform#

Rebase single qubit gates into Rz, Rx.

static RebaseToTket() pytket.transform.Transform#

Rebase from any gate set into TK1, CX.

static ReduceSingles() pytket.transform.Transform#

Reduces each sequence of single-qubit rotations into a single TK1.

static RemoveRedundancies() pytket.transform.Transform#

Applies a collection of simple optimisations, such as removing gate-inverse pairs, merging similar rotation gates, and removing identity gates. Preserves the gate set and any placement/orientation of multi-qubit gates.

static SynthesisePauliGraph(synth_strat: pytket.transform.PauliSynthStrat = PauliSynthStrat.Sets, cx_config: pytket.circuit.CXConfigType = CXConfigType.Snake) pytket.transform.Transform#

Synthesises Pauli Graphs.

static ThreeQubitSquash(target_2qb_gate: pytket.circuit.OpType = OpType.CX) pytket.transform.Transform#

Squash three-qubit subcircuits into subcircuits having fewer 2-qubit gates of the target type, when possible. The supported target types are CX (default) and TK2.

static UCCSynthesis(synth_strat: pytket.transform.PauliSynthStrat = PauliSynthStrat.Sets, cx_config: pytket.circuit.CXConfigType = CXConfigType.Snake) pytket.transform.Transform#

Synthesises UCC circuits in the form that Term Sequencing provides them.

static ZZPhaseToRz() pytket.transform.Transform#

Fixes all ZZPhase gate angles to [-1, 1) half turns.

__init__(self: pytket.transform.Transform, arg0: Callable[[pytket.circuit.Circuit], bool]) None#
apply(self: pytket.transform.Transform, circuit: pytket.circuit.Circuit) bool#

Performs the transformation on the circuit in place.

Parameters:

circuit – The circuit to be transformed

Returns:

True if any changes were made, else False

static repeat(transform: pytket.transform.Transform) pytket.transform.Transform#

Applies a given Transform repeatedly to a circuit until no further changes are made (i.e. it no longer returns True). apply() will return True if at least one run returned True.

Parameters:

transform – The Transform to be applied repeatedly

Returns:

a new Transform representing the iteration

static round_angles(n: int, only_zeros: bool = False) pytket.transform.Transform#
Parameters:

only_zeros – if True, only round angles less than \(\pi / 2^{n+1}\) to zero, leave other angles alone (default False)

static sequence(sequence: Sequence[pytket.transform.Transform]) pytket.transform.Transform#

Composes a list of Transforms together in sequence. The apply() method will return True if ANY of the individual Transforms returned True.

Parameters:

sequence – The list of Transforms to be composed

Returns:

the combined Transform

static while_repeat(condition: pytket.transform.Transform, body: pytket.transform.Transform) pytket.transform.Transform#

Repeatedly applies the condition Transform until it returns False, running body in between each condition application. Intuitively, this corresponds to “WHILE condition DO body”.

Parameters:
  • condition – The Transform to be applied repeatedly as the condition of a loop

  • body – The Transform to be applied after each successful test of the condition

Returns:

a new Transform representing the iteration

pytket.transform.separate_classical(circ: pytket.circuit.Circuit) tuple[pytket.circuit.Circuit, pytket.circuit.Circuit]#

Separate the input circuit into a ‘main’ circuit and a classical ‘post-processing’ circuit, which are equivalent to the original when composed.

Parameters:

circ – circuit to be separated