# Example: Customizing Randomized Compiling with Cycle Markers

Randomized Compiling is based on breaking the cycles contained in a circuit into two groups: easy cycles and hard cycles. In a typical usage scenario, hard cycles contain operations with significant miscalibration or crosstalk, such as entangling gates. In contrast, easy cycles contain operations which can be executed with high fidelity, such as single-qubit gates.

In True-Q™, the user can specify which cycles are easy or hard by setting the marker attribute of the cycles in the circuit: if a cycle has its marker set to 0 it is considered as easy; otherwise it is considered hard.

The randomly_compile() function creates a collection of randomly compiled circuits that each describe an equivalent but physically different implementation of the original circuit. Specifically, for each hard cycle $U$ in the circuit, randomly_compile() picks random Pauli operators $P$ and $Q$, such that $U = PUQ$ and, as an intermediate step, replaces the cycle $U$ by three consecutive cycles $[Q, U, P]$. The additional cycles $P$ and $Q$ are then merged into any existing adjacent single-qubit cycles, as long as the latter have their marker attribute set to 0 and can be interpreted as easy cycles. This compilation step where we fold the random gates into the neighbouring easy cycles allows the depth of a circuit to remain unchanged by applying randomized compiling.

Note

Randomized compiling produces a new circuit collection after each call, so the output of this example will be different if it’s executed again.

## Default configuration: equal cycle markers

By default, if randomly_compile() is called on a circuit without explicitly specifying the hard cycles (i.e. the circuit contains only zero marker values), it interprets that as the user intending the hard cycles to consist of all cycles containing two-qubit gates, and the easy cycles to consist of everything else.

For example, consider a circuit which applies alternating cycles, with an $X$ gate on qubit 0 in one cycle and a $CZ$ gate on qubits 0 and 1 in the other cycle. To be fully explicit, we set the marker arguments to zero (which would otherwise also be the default value):

:

import trueq as tq

cycle1 = tq.Cycle({0: tq.Gate.x}, marker=0)
cycle2 = tq.Cycle({(0, 1): tq.Gate.cz}, marker=0)
circuit = tq.Circuit([cycle1, cycle2, cycle1, cycle2, cycle1])

# Display the circuit
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.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, 1): 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. (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, 1): 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. (0): Gate.x Name: Gate.x Aliases: Gate.x Gate.cliff1 Generators: 'X': 180.0 Matrix: 1.00 1.00

Note that when all cycle markers are set to 0, they are not displayed in the output.

Next, we generate a set of randomly compiled versions of this circuit:

:

compiled_circuits = tq.randomly_compile(circuit)

# Display an example circuit:
compiled_circuits

:

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: protocol: RC twirl: Paulis on [0, 1] 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.z Name: Gate.z Aliases: Gate.z Gate.cliff3 Generators: 'Z': 180.0 Matrix: 1.00 -1.00 1 Marker 1 Compilation tools may only recompile cycles with equal markers. (0, 1): 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. (0): Gate.id Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Likeness: Identity Generators: 'I': 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 Marker 2 Compilation tools may only recompile cycles with equal markers. (0, 1): 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. (0): Gate.x Name: Gate.x Aliases: Gate.x Gate.cliff1 Generators: 'X': -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

This circuit now has two new explicit cycle markers for the two-qubit gates, and the original single-qubit gates have been absorbed into random twirling gates. The overall circuit length is preserved.

## Custom configuration: different cycle markers

If there are cycles in the circuit with non-zero markers, then the randomly_compile() function interprets them as hard cycles.

For example, consider again the circuit from above but this time with a third cycle in the middle containing a single-qubit $X$ gate that is uniquely marked:

:

cycle1 = tq.Cycle({0: tq.Gate.x})
cycle2 = tq.Cycle({(0, 1): tq.Gate.cz})
cycle3 = tq.Cycle({0: tq.Gate.x}, marker=1)
circuit = tq.Circuit([cycle1, cycle2, cycle3, cycle2, cycle1])

# Display the circuit:
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.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, 1): 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 1 Marker 1 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, 1): 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. (0): Gate.x Name: Gate.x Aliases: Gate.x Gate.cliff1 Generators: 'X': 180.0 Matrix: 1.00 1.00

Now, when we generate a set of randomly compiled versions of this circuit, the resulting circuits will have randomizations inserted only around the marked gate:

:

compiled_circuits = tq.randomly_compile(circuit)

# Display an example circuit:
compiled_circuits

:

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: protocol: RC twirl: Paulis on [0, 1] 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, 1): 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. (0): Gate.y Name: Gate.y Aliases: Gate.y Gate.cliff2 Generators: 'Y': -180.0 Matrix: 1.00 -1.00 (1): Gate.y Name: Gate.y Aliases: Gate.y Gate.cliff2 Generators: 'Y': -180.0 Matrix: 1.00 -1.00 1 Marker 1 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.00 -1.00 (1): Gate.y Name: Gate.y Aliases: Gate.y Gate.cliff2 Generators: 'Y': -180.0 Matrix: 1.00 -1.00 Marker 0 Compilation tools may only recompile cycles with equal markers. (0, 1): 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. (0): Gate.x Name: Gate.x Aliases: Gate.x Gate.cliff1 Generators: 'X': 180.0 Matrix: 1.00 1.00

When randomly_compile() is given an input circuit with at least one non-zero marker, these cycles are treated as hard cycles. In contrast, when there are no markers specified, any cycles containing two-qubit gates will be marked and treated as hard cycles. Any cycle which is not treated as a hard cycle is treated as an easy cycle.

In summary, a cycle marker provides a configuration option for Randomized Compiling to specify where random gates can be inserted and which cycles to leave untouched.