Download

Download this file as Jupyter notebook: rc_kak.ipynb.

Example: Randomly Compiling Arbitrary Multi-qudit Gates

This example shows how to use the RCKak compiler pass to randomly compile circuits with non-Clifford multi-qudit gates. Randomizing and correction cycles can be applied around hard cycles in the circuit without the need to first convert all entangling gates into Clifford operations.

Generating randomly compiled circuits

Consider some circuit with alternating easy and hard cycles, where entangling gates are considered to be hard, and single-qubit gates are considered to be easy:

[2]:
import trueq as tq
import numpy as np
import trueq.compilation as tqc
from trueq.config import fsim_factory
from trueq import CircuitCollection

cycle1 = {1: tq.Gate.h, 4: tq.Gate.h}
cycle2 = {(0, 1): tq.Gate.random(4)}
cycle3 = {1: tq.Gate.t, 3: tq.Gate.random(2)}
cycle4 = tq.Cycle({(1, 3): fsim_factory(11, 13)})

circuit = tq.Circuit([cycle1, cycle2, cycle3, cycle4] * 2)
circuit += cycle1
circuit.measure_all()
circuit.draw()
[2]:
0 1 3 4 Key: Labels: (1,) Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: Z: 127.28 X: 127.28 0.71 0.71 0.71 -0.71 H Labels: (4,) Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: Z: 127.28 X: 127.28 0.71 0.71 0.71 -0.71 H Labels: (0, 1) Name: Gate Locally Equivalent: Non-Clifford Generators: ZX: -96.33 ZY: -69.70 IX: 64.54 XY: -58.04 XZ: 51.53 YY: 51.52 XI: -38.77 ... 0.65 -0.04j 0.46 0.22j 0.27 -0.24j -0.21 0.38j -0.61 -0.07j 0.27 -0.08j 0.04 0.00j -0.62 0.39j -0.26 0.31j 0.75 0.05j 0.03 -0.12j 0.28 -0.41j -0.17 -0.06j -0.22 -0.20j 0.82 -0.43j 0.06 -0.15j Labels: (1,) Name: Gate.t Aliases: Gate.t Generators: Z: 45.00 1.00 0.71 0.71j T Labels: (3,) Name: Gate Generators: Y: -76.52 X: -32.90 Z: -18.23 0.75 0.08j 0.63 0.21j -0.58 0.31j 0.72 -0.21j Labels: (1, 3) Name: FSim Parameters: theta: 11.00 phi: 13.00 Locally Equivalent: Non-Clifford Generators: YY: 11.00 XX: 11.00 ZI: 6.50 ZZ: -6.50 IZ: 6.50 YX: -0.00 XY: 0.00 1.00 -0.06j 0.98 -0.06j -0.01 -0.19j -0.01 -0.19j 0.98 -0.06j 0.99 0.17j Labels: (1,) Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: Z: 127.28 X: 127.28 0.71 0.71 0.71 -0.71 H Labels: (4,) Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: Z: 127.28 X: 127.28 0.71 0.71 0.71 -0.71 H Labels: (0, 1) Name: Gate Locally Equivalent: Non-Clifford Generators: ZX: -96.33 ZY: -69.70 IX: 64.54 XY: -58.04 XZ: 51.53 YY: 51.52 XI: -38.77 ... 0.65 -0.04j 0.46 0.22j 0.27 -0.24j -0.21 0.38j -0.61 -0.07j 0.27 -0.08j 0.04 0.00j -0.62 0.39j -0.26 0.31j 0.75 0.05j 0.03 -0.12j 0.28 -0.41j -0.17 -0.06j -0.22 -0.20j 0.82 -0.43j 0.06 -0.15j Labels: (1,) Name: Gate.t Aliases: Gate.t Generators: Z: 45.00 1.00 0.71 0.71j T Labels: (3,) Name: Gate Generators: Y: -76.52 X: -32.90 Z: -18.23 0.75 0.08j 0.63 0.21j -0.58 0.31j 0.72 -0.21j Labels: (1, 3) Name: FSim Parameters: theta: 11.00 phi: 13.00 Locally Equivalent: Non-Clifford Generators: YY: 11.00 XX: 11.00 ZI: 6.50 ZZ: -6.50 IZ: 6.50 YX: -0.00 XY: 0.00 1.00 -0.06j 0.98 -0.06j -0.01 -0.19j -0.01 -0.19j 0.98 -0.06j 0.99 0.17j Labels: (1,) Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: Z: 127.28 X: 127.28 0.71 0.71 0.71 -0.71 H Labels: (4,) Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: Z: 127.28 X: 127.28 0.71 0.71 0.71 -0.71 H 1 Labels: (0,) Name: Meas M Labels: (1,) Name: Meas M Labels: (3,) Name: Meas M Labels: (4,) Name: Meas M

This circuit contains non-Clifford entangling gates which are not handled by the randomly_compile() protocol by default. To randomly compile this circuit, one approach is to first decompose the circuit into a logically equivalent circuit using a specified Clifford entangler:

[3]:
rc_circuits = tq.randomly_compile(circuit, entangler=tq.Gate.cx)
rc_circuits[0].draw()
[3]:
0 1 3 4 Key: twirl: Paulis on [0, 1, 3, 4] protocol: RC Labels: (0,) Name: Gate Generators: Y: -213.26 Z: 37.03 X: 34.75 -0.18 -0.33j 0.83 0.42j -0.65 -0.66j -0.36 -0.07j Labels: (1,) Name: Gate Generators: Z: 122.97 Y: -108.75 X: 2.26 -0.33 -0.68j 0.52 -0.40j -0.54 0.38j 0.55 0.52j Labels: (3,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID Labels: (4,) Name: Gate.cliff13 Aliases: Gate.cliff13 Generators: Z: 127.28 X: -127.28 0.71 -0.71 -0.71 -0.71 13 2 Labels: (0, 1) Name: cx Aliases: Gate.cx Gate.cnot Parameters: Locally Equivalent: CNOT Generators: ZX: -90.00 IX: 90.00 ZI: 90.00 1.00 1.00 1.00 1.00 CX CX Labels: (0,) Name: Gate Generators: Y: -89.81 X: -6.80 Z: -6.80 0.71 0.05j 0.71 0.05j -0.71 0.05j 0.71 -0.05j Labels: (1,) Name: Gate Generators: X: 180.00 Y: -0.89 1.00 0.00j 1.00 -0.00j Labels: (3,) Name: Gate.y Aliases: Gate.y Gate.cliff2 Generators: Y: -180.00 1.00 -1.00 Y Labels: (4,) Name: Gate.y Aliases: Gate.y Gate.cliff2 Generators: Y: -180.00 1.00 -1.00 Y 3 Labels: (0, 1) Name: cx Aliases: Gate.cx Gate.cnot Parameters: Locally Equivalent: CNOT Generators: ZX: -90.00 IX: 90.00 ZI: 90.00 1.00 1.00 1.00 1.00 CX CX Labels: (0,) Name: Gate.cliff6 Aliases: Gate.cliff6 Generators: Y: -90.00 0.71j 0.71j -0.71j 0.71j 6 Labels: (1,) Name: Gate Generators: Y: -151.60 X: -97.05 0.84 0.54j -0.84 0.54j Labels: (3,) Name: Gate.z Aliases: Gate.z Gate.cliff3 Generators: Z: -180.00 1.00 -1.00 Z Labels: (4,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID 4 Labels: (0, 1) Name: cx Aliases: Gate.cx Gate.cnot Parameters: Locally Equivalent: CNOT Generators: ZX: -90.00 IX: 90.00 ZI: 90.00 1.00 1.00 1.00 1.00 CX CX Labels: (0,) Name: Gate Generators: Z: 170.19 X: -35.02 Y: -30.46 0.89 -0.37j -0.11 0.24j -0.25 -0.08j -0.87 0.42j Labels: (1,) Name: Gate Generators: Y: -111.26 X: 106.06 Z: 92.91 0.38 -0.35j 0.85 0.05j 0.01 -0.86j -0.38 0.36j Labels: (3,) Name: Gate Generators: Z: 90.01 X: -88.71 Y: 34.76 0.66 0.36j -0.64 -0.18j -0.59 0.30j -0.58 0.47j Labels: (4,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID 5 Labels: (1, 3) Name: cx Aliases: Gate.cx Gate.cnot Parameters: Locally Equivalent: CNOT Generators: ZX: -90.00 IX: 90.00 ZI: 90.00 1.00 1.00 1.00 1.00 CX CX Labels: (0,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID Labels: (1,) Name: Gate Generators: X: 77.30 Z: 77.30 Y: -63.72 0.55 0.45j 0.55 0.45j 0.55 -0.45j -0.55 0.45j Labels: (3,) Name: Gate Generators: Z: -6.50 1.00 0.06j 1.00 -0.06j Labels: (4,) Name: Gate.x Aliases: Gate.x Gate.cliff1 Generators: X: 180.00 1.00 1.00 X 6 Labels: (1, 3) Name: cx Aliases: Gate.cx Gate.cnot Parameters: Locally Equivalent: CNOT Generators: ZX: -90.00 IX: 90.00 ZI: 90.00 1.00 1.00 1.00 1.00 CX CX Labels: (0,) Name: Gate.x Aliases: Gate.x Gate.cliff1 Generators: X: 180.00 1.00 1.00 X Labels: (1,) Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: X: -127.28 Z: -127.28 0.71j 0.71j 0.71j -0.71j H Labels: (3,) Name: Gate Generators: Z: 169.00 1.00 0.10j -1.00 0.10j Labels: (4,) Name: Gate.y Aliases: Gate.y Gate.cliff2 Generators: Y: -180.00 1.00 -1.00 Y 7 Labels: (1, 3) Name: cx Aliases: Gate.cx Gate.cnot Parameters: Locally Equivalent: CNOT Generators: ZX: -90.00 IX: 90.00 ZI: 90.00 1.00 1.00 1.00 1.00 CX CX Labels: (0,) Name: Gate Generators: X: 150.08 Z: 54.97 Y: 24.45 -0.18 -0.33j -0.83 -0.42j -0.65 -0.66j 0.36 0.07j Labels: (1,) Name: Gate Generators: Y: -271.06 X: 42.81 Z: -5.07 -0.56 0.48j 0.45 -0.51j -0.58 0.35j -0.57 0.46j Labels: (3,) Name: Gate Generators: X: 72.52 Y: 63.97 Z: 63.97 0.43 0.56j 0.56 -0.43j 0.50 0.50j -0.50 0.50j Labels: (4,) Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: X: -127.28 Z: -127.28 0.71j 0.71j 0.71j -0.71j H 8 Labels: (0, 1) Name: cx Aliases: Gate.cx Gate.cnot Parameters: Locally Equivalent: CNOT Generators: ZX: -90.00 IX: 90.00 ZI: 90.00 1.00 1.00 1.00 1.00 CX CX Labels: (0,) Name: Gate Generators: Y: 89.81 Z: 6.80 X: -6.80 0.71 -0.05j -0.71 0.05j 0.71 0.05j 0.71 0.05j Labels: (1,) Name: Gate Generators: Z: 179.43 1.00 0.00j -1.00 0.00j Labels: (3,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID Labels: (4,) Name: Gate.y Aliases: Gate.y Gate.cliff2 Generators: Y: -180.00 1.00 -1.00 Y 9 Labels: (0, 1) Name: cx Aliases: Gate.cx Gate.cnot Parameters: Locally Equivalent: CNOT Generators: ZX: -90.00 IX: 90.00 ZI: 90.00 1.00 1.00 1.00 1.00 CX CX Labels: (0,) Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: X: -127.28 Z: -127.28 0.71j 0.71j 0.71j -0.71j H Labels: (1,) Name: Gate Generators: Z: -65.25 0.84 0.54j 0.84 -0.54j Labels: (3,) Name: Gate.y Aliases: Gate.y Gate.cliff2 Generators: Y: -180.00 1.00 -1.00 Y Labels: (4,) Name: Gate.z Aliases: Gate.z Gate.cliff3 Generators: Z: -180.00 1.00 -1.00 Z 10 Labels: (0, 1) Name: cx Aliases: Gate.cx Gate.cnot Parameters: Locally Equivalent: CNOT Generators: ZX: -90.00 IX: 90.00 ZI: 90.00 1.00 1.00 1.00 1.00 CX CX Labels: (0,) Name: Gate Generators: Y: -154.57 Z: -27.67 X: 5.03 0.25 0.08j 0.87 -0.42j -0.89 0.37j 0.11 -0.24j Labels: (1,) Name: Gate Generators: Y: -111.26 X: 106.06 Z: 92.91 0.38 -0.35j 0.85 0.05j 0.01 -0.86j -0.38 0.36j Labels: (3,) Name: Gate Generators: X: 97.94 Z: 96.53 Y: -64.90 -0.64 -0.18j -0.66 -0.36j -0.58 0.47j 0.59 -0.30j Labels: (4,) Name: Gate.x Aliases: Gate.x Gate.cliff1 Generators: X: 180.00 1.00 1.00 X 11 Labels: (1, 3) Name: cx Aliases: Gate.cx Gate.cnot Parameters: Locally Equivalent: CNOT Generators: ZX: -90.00 IX: 90.00 ZI: 90.00 1.00 1.00 1.00 1.00 CX CX Labels: (0,) Name: Gate.y Aliases: Gate.y Gate.cliff2 Generators: Y: -180.00 1.00 -1.00 Y Labels: (1,) Name: Gate Generators: X: 77.30 Z: 77.30 Y: -63.72 0.55 0.45j 0.55 0.45j 0.55 -0.45j -0.55 0.45j Labels: (3,) Name: Gate Generators: X: -179.71 Y: -10.20 -1.00 0.06j -1.00 -0.06j Labels: (4,) Name: Gate.x Aliases: Gate.x Gate.cliff1 Generators: X: 180.00 1.00 1.00 X 12 Labels: (1, 3) Name: cx Aliases: Gate.cx Gate.cnot Parameters: Locally Equivalent: CNOT Generators: ZX: -90.00 IX: 90.00 ZI: 90.00 1.00 1.00 1.00 1.00 CX CX Labels: (0,) Name: Gate.x Aliases: Gate.x Gate.cliff1 Generators: X: 180.00 1.00 1.00 X Labels: (1,) Name: Gate.cliff6 Aliases: Gate.cliff6 Generators: Y: -90.00 0.71j 0.71j -0.71j 0.71j 6 Labels: (3,) Name: Gate Generators: Z: -349.00 -1.00 0.10j -1.00 -0.10j Labels: (4,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID 13 Labels: (1, 3) Name: cx Aliases: Gate.cx Gate.cnot Parameters: Locally Equivalent: CNOT Generators: ZX: -90.00 IX: 90.00 ZI: 90.00 1.00 1.00 1.00 1.00 CX CX Labels: (0,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID Labels: (1,) Name: Gate Generators: Y: -123.57 X: -123.57 Z: -7.74 0.05 0.04j 0.75 0.66j -0.66 0.75j 0.04 -0.05j Labels: (3,) Name: Gate Generators: Y: -74.53 Z: 74.53 X: -65.74 0.50 -0.50j 0.50 0.50j -0.56 0.43j 0.43 0.56j Labels: (4,) Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: X: -127.28 Z: -127.28 0.71j 0.71j 0.71j -0.71j H 1 Labels: (0,) Name: Meas M Labels: (1,) Name: Meas M Labels: (3,) Name: Meas M Labels: (4,) Name: Meas M

which increases the circuit depth (see Example: Randomized Compilation with different Compilation Options).

An alterative approach is to use custom randomizing operations for each gate in the circuit. One-qudit gates in marked cycles are twirled by the one-qudit Pauli group. For two-qubit gates, each randomizing operation is sampled uniformly from the set of local operations such that the corresponding correction cycle may also be applied locally. Any multi-qudit or larger multi-qubit gates are randomized with local operations found via empirical decomposition.

This variant of randomized compiling can implemented using the RCKak compiler pass:

[4]:
def rc_kak(circuit, n_compilations=30, local=True):
    circuits = CircuitCollection(circuit.__copy__() for _ in range(n_compilations))
    passes = [
        tqc.MarkCycles(),  # mark any cycles with two-qubit gates
        tqc.RCKak(local=local),  # apply randomizing cycles around marked cycles
        tqc.Merge(),
        tqc.RemoveEmptyCycle(),
    ]
    return tqc.Compiler(passes).compile(circuits)
[5]:
kak_rc_circuits = rc_kak(circuit, n_compilations=30, local=True)
kak_rc_circuits[0].draw()
[5]:
0 1 3 4 Key: protocol: RC Labels: (0,) Name: Gate Generators: Y: -162.86 X: 68.48 Z: 34.45 -0.19 -0.38 -0.90j -0.38 0.90j 0.19 Labels: (1,) Name: Gate Generators: Y: -246.15 X: -21.40 Z: 21.40 -0.56 -0.07j 0.82 0.07j -0.82 0.07j -0.56 0.07j Labels: (4,) Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: Z: 127.28 X: 127.28 0.71 0.71 0.71 -0.71 H 2 Labels: (0, 1) Name: Gate Locally Equivalent: Non-Clifford Generators: ZX: -96.33 ZY: -69.70 IX: 64.54 XY: -58.04 XZ: 51.53 YY: 51.52 XI: -38.77 ... 0.65 -0.04j 0.46 0.22j 0.27 -0.24j -0.21 0.38j -0.61 -0.07j 0.27 -0.08j 0.04 0.00j -0.62 0.39j -0.26 0.31j 0.75 0.05j 0.03 -0.12j 0.28 -0.41j -0.17 -0.06j -0.22 -0.20j 0.82 -0.43j 0.06 -0.15j Labels: (0,) Name: Gate Generators: Z: -155.10 X: 70.83 Y: -57.67 0.86 -0.39 -0.32j -0.39 0.32j -0.86 Labels: (1,) Name: Gate Generators: Z: 129.93 Y: -69.09 X: -19.15 0.65 -0.60j 0.33 0.33j -0.45 -0.11j -0.18 0.87j Labels: (3,) Name: Gate Generators: X: 106.60 Z: -85.49 Y: 34.93 -0.49 0.44j 0.65 -0.38j 0.75 0.08j 0.63 0.21j 3 Labels: (1, 3) Name: FSim Parameters: phi: 13.00 theta: 11.00 Locally Equivalent: Non-Clifford Generators: YY: 11.00 XX: 11.00 ZI: 6.50 ZZ: -6.50 IZ: 6.50 YX: -0.00 XY: 0.00 1.00 -0.06j 0.98 -0.06j -0.01 -0.19j -0.01 -0.19j 0.98 -0.06j 0.99 0.17j Labels: (0,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 -1.00 -1.00 ID Labels: (1,) Name: Gate Generators: Y: 252.69 X: -60.69 Z: 60.69 -0.63 -0.32j -0.71 0.63 0.32j -0.71 Labels: (3,) Name: Gate Generators: X: 175.02 Y: 42.04 0.89 -0.45j 1.00 Labels: (4,) Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: Z: 127.28 X: 127.28 0.71 0.71 0.71 -0.71 H 4 Labels: (0, 1) Name: Gate Locally Equivalent: Non-Clifford Generators: ZX: -96.33 ZY: -69.70 IX: 64.54 XY: -58.04 XZ: 51.53 YY: 51.52 XI: -38.77 ... 0.65 -0.04j 0.46 0.22j 0.27 -0.24j -0.21 0.38j -0.61 -0.07j 0.27 -0.08j 0.04 0.00j -0.62 0.39j -0.26 0.31j 0.75 0.05j 0.03 -0.12j 0.28 -0.41j -0.17 -0.06j -0.22 -0.20j 0.82 -0.43j 0.06 -0.15j Labels: (0,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 -1.00 -1.00 ID Labels: (1,) Name: Gate Generators: Y: 173.58 X: 47.64 -0.71 -0.71j 0.97 0.25j Labels: (3,) Name: Gate Generators: Y: 95.72 Z: 45.04 X: -31.64 0.49 -0.45j -0.65 0.38j 0.75 0.08j 0.63 0.21j 5 Labels: (1, 3) Name: FSim Parameters: phi: 13.00 theta: 11.00 Locally Equivalent: Non-Clifford Generators: YY: 11.00 XX: 11.00 ZI: 6.50 ZZ: -6.50 IZ: 6.50 YX: -0.00 XY: 0.00 1.00 -0.06j 0.98 -0.06j -0.01 -0.19j -0.01 -0.19j 0.98 -0.06j 0.99 0.17j Labels: (1,) Name: Gate Generators: X: 138.83 Z: -138.83 Y: 33.72 0.63 0.32j -0.71 -0.63 -0.32j -0.71 Labels: (3,) Name: Gate Generators: Y: 174.91 X: -42.48 -0.89 0.46j 1.00 Labels: (4,) Name: Gate.h Aliases: Gate.h Gate.f Gate.cliff12 Generators: Z: 127.28 X: 127.28 0.71 0.71 0.71 -0.71 H 1 Labels: (0,) Name: Meas M Labels: (1,) Name: Meas M Labels: (3,) Name: Meas M Labels: (4,) Name: Meas M

By default, randomizing and correction gates are applied around all gates in the hard cycles. To specify that gates should be applied to idling qubits as well, set the local argument to False:

[6]:
rc_kak(circuit, n_compilations=30, local=False)[0].draw()
[6]:
0 1 3 4 Key: protocol: RC Labels: (0,) Name: Gate Generators: Z: -130.33 X: -102.17 Y: -70.53 -0.72 -0.57 0.39j -0.57 -0.39j 0.72 Labels: (1,) Name: Gate Generators: Z: 107.52 X: -107.52 Y: -6.89 0.24 -0.69j 0.04 0.69j -0.04 0.69j 0.24 0.69j Labels: (3,) Name: Gate.id Aliases: Gate.id Gate.i Gate.cliff0 Locally Equivalent: Identity Generators: I: 0.00 1.00 1.00 ID Labels: (4,) Name: Gate.cliff13 Aliases: Gate.cliff13 Generators: Z: 127.28 X: -127.28 0.71 -0.71 -0.71 -0.71 13 2 Labels: (0, 1) Name: Gate Locally Equivalent: Non-Clifford Generators: ZX: -96.33 ZY: -69.70 IX: 64.54 XY: -58.04 XZ: 51.53 YY: 51.52 XI: -38.77 ... 0.65 -0.04j 0.46 0.22j 0.27 -0.24j -0.21 0.38j -0.61 -0.07j 0.27 -0.08j 0.04 0.00j -0.62 0.39j -0.26 0.31j 0.75 0.05j 0.03 -0.12j 0.28 -0.41j -0.17 -0.06j -0.22 -0.20j 0.82 -0.43j 0.06 -0.15j Labels: (0,) Name: Gate Generators: Z: 169.78 Y: 62.47 -0.01 -0.94j -0.35 0.35 -0.01 0.94j Labels: (1,) Name: Gate Generators: X: 192.72 Y: -126.89 Z: -91.00 -0.62 0.13j 0.59 -0.50j -0.22 -0.74j -0.45 -0.45j Labels: (3,) Name: Gate Generators: Z: 129.00 X: 109.15 Y: -33.87 0.75 0.08j 0.63 0.21j 0.64 -0.18j -0.75 0.05j Labels: (4,) Name: Gate.z Aliases: Gate.z Gate.cliff3 Generators: Z: -180.00 1.00 -1.00 Z 3 Labels: (1, 3) Name: FSim Parameters: phi: 13.00 theta: 11.00 Locally Equivalent: Non-Clifford Generators: YY: 11.00 XX: 11.00 ZI: 6.50 ZZ: -6.50 IZ: 6.50 YX: -0.00 XY: 0.00 1.00 -0.06j 0.98 -0.06j -0.01 -0.19j -0.01 -0.19j 0.98 -0.06j 0.99 0.17j Labels: (0,) Name: Gate Generators: Y: 219.14 Z: -118.59 -0.57 0.39j -0.72 0.72 -0.57 -0.39j Labels: (1,) Name: Gate Generators: Y: -87.93 Z: -40.34 X: 15.02 -0.38 0.62j 0.04 0.69j 0.19 -0.66j 0.24 0.69j Labels: (3,) Name: Gate Generators: Z: -12.05 1.00 0.98 -0.21j Labels: (4,) Name: Gate.cliff6 Aliases: Gate.cliff6 Generators: Y: -90.00 0.71 0.71 -0.71 0.71 6 4 Labels: (0, 1) Name: Gate Locally Equivalent: Non-Clifford Generators: ZX: -96.33 ZY: -69.70 IX: 64.54 XY: -58.04 XZ: 51.53 YY: 51.52 XI: -38.77 ... 0.65 -0.04j 0.46 0.22j 0.27 -0.24j -0.21 0.38j -0.61 -0.07j 0.27 -0.08j 0.04 0.00j -0.62 0.39j -0.26 0.31j 0.75 0.05j 0.03 -0.12j 0.28 -0.41j -0.17 -0.06j -0.22 -0.20j 0.82 -0.43j 0.06 -0.15j Labels: (0,) Name: Gate Generators: X: -139.59 Y: 1.18 0.35 -0.01 0.94j 0.01 0.94j 0.35 Labels: (1,) Name: Gate Generators: X: -119.70 Z: 91.04 Y: -9.89 0.02 -0.64j 0.34 0.69j 0.22 0.74j 0.45 0.45j Labels: (3,) Name: Gate Generators: Y: 81.17 Z: 53.57 X: -30.90 0.75 0.08j -0.63 -0.21j 0.33 0.57j 0.23 0.71j Labels: (4,) Name: Gate.z Aliases: Gate.z Gate.cliff3 Generators: Z: -180.00 1.00 -1.00 Z 5 Labels: (1, 3) Name: FSim Parameters: phi: 13.00 theta: 11.00 Locally Equivalent: Non-Clifford Generators: YY: 11.00 XX: 11.00 ZI: 6.50 ZZ: -6.50 IZ: 6.50 YX: -0.00 XY: 0.00 1.00 -0.06j 0.98 -0.06j -0.01 -0.19j -0.01 -0.19j 0.98 -0.06j 0.99 0.17j Labels: (0,) Name: Gate.z Aliases: Gate.z Gate.cliff3 Generators: Z: -180.00 1.00 -1.00 Z Labels: (1,) Name: Gate Generators: Y: 70.12 Z: -67.97 X: -67.97 0.02 0.71j -0.71 0.02 0.71j 0.71 Labels: (3,) Name: Gate Generators: Z: 91.78 1.00 -0.03 1.00j Labels: (4,) Name: Gate.sy Aliases: Gate.sy Gate.cliff7 Generators: Y: 90.00 0.71 -0.71 0.71 0.71 SY 1 Labels: (0,) Name: Meas M Labels: (1,) Name: Meas M Labels: (3,) Name: Meas M Labels: (4,) Name: Meas M

We now have a CircuitCollection of randomly compiled circuits, each of which are logically equivalent to the original, with preserved two-qubit gates.

Comparing RC performance

We can compare the ideal output distribution of the circuit with the observed distribution obtained using a noisy simulator. Using our collection of randomly compiled circuits, we can estimate the ideal distribution by averaging noisy observations over the collection:

[7]:
# use an ideal simulator to obtain the ideal output distribution
sim = tq.Simulator()
ideal_result = sim.sample(circuit, n_shots=np.inf)

# create a noisy simulator to observe the output in the presence of overrotation noise
noisy_sim = tq.Simulator().add_overrotation(single_sys=0.01, multi_sys=0.1)
noisy_result = noisy_sim.sample(circuit, n_shots=np.inf)

# estimate the ideal distribution using the collection of circuits obtained from RCKak
kak_rc_result = sum(
    noisy_sim.sample(kak_circuit, n_shots=np.inf) for kak_circuit in kak_rc_circuits
)

# likewise using the collection of circuits obtained from RC with an additional
# decomposition step
rc_result = sum(
    noisy_sim.sample(rc_circuit, n_shots=np.inf) for rc_circuit in rc_circuits
)

# compare the total variation distance between the estimated distributions and the ideal
bare_tvd = noisy_result.tvd(ideal_result)
kak_rc_tvd = kak_rc_result.normalized().tvd(ideal_result)
rc_tvd = rc_result.normalized().tvd(ideal_result)

print("TOTAL VARIATION DISTANCE")
print("Noisy simulation without RC: {:.4f}".format(bare_tvd[0]))
print("Noisy simulation with RCKak: {:.4f}".format(kak_rc_tvd[0]))
print("Noisy simulation with RC (using entangler): {:.4f}".format(rc_tvd[0]))
TOTAL VARIATION DISTANCE
Noisy simulation without RC: inf
Noisy simulation with RCKak: 0.0557
Noisy simulation with RC (using entangler): inf
Warning: divide by zero encountered in divide
         (/home/jenkins/workspace/release trueq/trueq/results.py:489)
Warning: divide by zero encountered in divide
         (/home/jenkins/workspace/release trueq/trueq/results.py:489)

Imperfect coherent error suppression

Note that the randomizing operation implemented by RCKak is not a full twirl operation, and therefore not all coherent errors will be suppressed.

For example, consider a single cycle containing a YY rotation simulated with overrotation noise:

[8]:
circuit = tq.Circuit({(0, 1): tq.Gate.from_generators("YY", 45)})
circuit.measure_all()
circuit.draw()
[8]:
0 1 Key: Labels: (0, 1) Name: Gate Locally Equivalent: Non-Clifford Generators: YY: 45.00 0.92 0.38j 0.92 -0.38j -0.38j 0.92 0.38j 0.92 1 Labels: (0,) Name: Meas M Labels: (1,) Name: Meas M
[9]:
kak_rc_circuits = rc_kak(circuit, n_compilations=30, local=True)

# obtain the ideal output distribution
ideal_result = sim.sample(circuit, n_shots=np.inf)

# simulate with overrotation noise
noisy_sim = tq.Simulator().add_overrotation(multi_sys=0.1)
noisy_result = noisy_sim.sample(circuit, n_shots=np.inf)

# estimate using RCKak
kak_rc_result = sum(
    noisy_sim.sample(kak_circuit, n_shots=np.inf) for kak_circuit in kak_rc_circuits
)

# compare the total variation distance
bare_tvd = noisy_result.tvd(ideal_result)
kak_rc_tvd = kak_rc_result.normalized().tvd(ideal_result)

print("TOTAL VARIATION DISTANCE")
print("Noisy simulation without RC: {:.4f}".format(bare_tvd[0]))
print("Noisy simulation with RCKak: {:.4f}".format(kak_rc_tvd[0]))
TOTAL VARIATION DISTANCE
Noisy simulation without RC: 0.0288
Noisy simulation with RCKak: 0.0288

We observe that the error was not suppressed by randomized compiling in this case.

A Note on using RCKak for qudit gates and gates on more than two qubits

As mentioned above, RCKak inserts local randomizing and correction gates that depend on the gate to be randomized. For one-qudit and two-qubit gates, the group to sample from is calculated, and a randomization is always applied. For multi-qudit gates and larger multi-qubit gates, the group to sample from is not calculated, and instead randomization will be attempted numerically. If a solution is not found, randomizing and correction gates are not inserted.

However the RCKak pass can always be applied to cycles containing these gates without error:

[10]:
tq.settings.set_dim(3)

# Apply RCKak to a cycle containing two-qutrit gates
qutrit_rc_circuits = rc_kak(
    tq.Circuit({(0, 1): tq.Gate.random(9), (2, 3): tq.Gate.cx3}),
    n_compilations=30,
    local=True,
)
qutrit_rc_circuits[0].draw()
[10]:
0 1 2 3 Key: protocol: RC Labels: (2,) Name: Gate -0.19 0.98j 0.99 0.16j -1.00 -0.08j Labels: (3,) Name: Gate -0.11 0.20j -0.13 -0.19j -0.07 0.94j 0.23 -0.02j -0.78 -0.53j -0.11 -0.20j 0.85 -0.41j 0.23 -0.00j -0.10 0.21j 1 Labels: (0, 1) Name: Gate 0.02 0.01j 0.24 0.18j 0.07 0.31j 0.34 0.01j -0.13 -0.35j 0.36 0.37j -0.28 -0.16j 0.11 0.16j 0.29 0.23j 0.06 -0.14j 0.21 -0.19j 0.53 -0.35j 0.08 -0.02j -0.07 -0.16j -0.45 0.20j 0.05 -0.04j -0.26 0.34j 0.14 -0.05j 0.06 -0.13j -0.17 0.20j 0.02 -0.06j 0.06 -0.45j 0.03 -0.18j -0.19 0.28j -0.01 0.62j 0.07 -0.27j -0.07 0.29j -0.27 -0.19j 0.19 -0.27j -0.01 -0.08j -0.31 -0.17j -0.15 -0.13j -0.16 -0.10j -0.24 -0.41j 0.13 -0.35j -0.09 0.46j -0.27 0.10j 0.11 0.17j -0.18 0.21j -0.33 0.01j -0.16 -0.46j -0.36 -0.11j -0.10 0.15j 0.28 0.22j 0.05 -0.39j -0.40 0.20j 0.24 0.33j 0.02 -0.12j 0.09 -0.29j 0.07 0.14j 0.05 0.19j -0.26 -0.14j -0.39 -0.17j -0.30 -0.33j -0.54 -0.02j -0.13 0.06j 0.17 -0.24j 0.25 0.36j -0.11 -0.28j 0.23 -0.28j 0.14 0.23j -0.06 0.07j -0.24 0.23j -0.40 -0.16j 0.47 -0.15j -0.09 0.15j 0.16 0.09j 0.35 0.42j -0.14 0.08j 0.09 0.26j 0.25 0.08j 0.17 0.09j 0.04 -0.30j 0.12 -0.41j -0.48 0.20j 0.34 -0.05j -0.25 -0.19j -0.07 -0.03j 0.09 0.09j -0.41 -0.07j -0.12 -0.15j Labels: (2, 3) Name: Gate.cx3 Aliases: Gate.cx3 Gate.cnot3 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 CX CX Labels: (2,) Name: Gate -0.74 0.67j 0.27 -0.96j 0.14 0.99j Labels: (3,) Name: Gate -0.49 -0.81j -0.01 0.23j -0.18 -0.14j -0.19 -0.12j 0.22 -0.09j 0.95 -0.02j -0.03 0.23j -0.46 0.83j 0.20 -0.10j

Download

Download this file as Jupyter notebook: rc_kak.ipynb.