Quantum Capacity

import matplotlib.pyplot as plt
import numpy as np
import random
import trueq as tq

First, we demonstrate using QCAP in the simplest setting: we create a small circuit and compute its QCAP bound.

# make a circuit to assess
circuit = tq.Circuit(
    [
        {1: tq.Gate.x, (0, 2): tq.Gate.cz},
        {0: tq.Gate.h, 1: tq.Gate.h},
        {(1, 2): tq.Gate.cnot, (0, 4): tq.Gate.cz},
    ]
)

# generate a circuit collection to measure the QCAP
circuits = tq.make_qcap(circuit, [0, 4, 16, 32])

# run the circuits on your hardware or simulator
sim = tq.Simulator().add_overrotation(0.03)
sim.run(circuits)

# generate the QCAP bound
tq.qcap_bound(circuit, circuits)
QCAP
Quantum Capacity
Paulis
(0, 1, 2, 4)
Key:
  • labels: (0, 1, 2, 4)
  • protocol: QCAP
  • twirl: (('P', 0), ('P', 1), ('P', 2), ('P', 4))
${e}_{IU}$
The inferred upper bound on the process infidelity of a circuit if it were run under RC.
1.7e-02 (1.2e-03)
0.016528244896301114, 0.0011849917156419787


Next, we perform a small study demonstrating the effectiveness of the QCAP bound on the family of random circuits which use the following hard cycles:

hard_cycles = [
    tq.Cycle({(0, 1): tq.Gate.cz, (2, 3): tq.Gate.cz}),
    tq.Cycle({(0, 2): tq.Gate.cz, (1, 3): tq.Gate.cz}),
    tq.Cycle({(0, 3): tq.Gate.cz, (1, 2): tq.Gate.cz}),
]

First, we use the QCAP assessment to measure the process infidelity of each of these hard cycles.

qcap_circuits = tq.make_qcap(hard_cycles, [4, 16])
sim.run(qcap_circuits)
qcap_fit = qcap_circuits.fit()

Then, we generate a random circuit using these hard cycles interleaved with single qubit cycles for a number of circuit depths. In each instance, we randomly compile the random circuit 20 times; QCAP bounds the performance of circuits whose noise profile has been tailored by RC.

def make_random_circuit(depth):
    circuit = tq.Circuit()
    for _ in range(depth):
        circuit += {q: tq.Gate.random(2) for q in range(4)}
        circuit += random.choice(hard_cycles)
    circuit += {q: tq.Gate.random(2) for q in range(4)}
    circuit.measure_all()
    circuit.key = tq.Key(depth=depth)
    return circuit


random_circuits = tq.CircuitCollection()
depths = list(range(5, 30, 5))
for depth in depths:
    bare_circuit = make_random_circuit(depth)
    random_circuits += bare_circuit
    random_circuits += tq.randomly_compile(bare_circuit, 20)

sim.run(random_circuits, 1000)

Finally, we collect and plot the data.

qcaps = np.empty((len(depths), 2))
rc_tvds = np.empty((len(depths), 2))
for idx, depth in enumerate(depths):
    bare_circuit = random_circuits.subset(protocol=["RC"], depth=depth)[0]
    rc_circuits = random_circuits.subset(protocol="RC", depth=depth)

    # compute the QCAP bound for this circuit
    qcaps[idx, :] = tq.qcap_bound(bare_circuit, qcap_fit).e_IU[1:]

    # compute the TVD from the RC results to the ideal bitstring distribution
    ideal_probs = tq.Simulator().sample(bare_circuit, float("inf"))
    rc_tvds[idx, :] = rc_circuits.sum_results().tvd(ideal_probs)

plt.errorbar(depths, qcaps[:, 0], yerr=2.96 * qcaps[:, 1], label="QCAP Bound")
plt.errorbar(depths, rc_tvds[:, 0], yerr=2.96 * rc_tvds[:, 1], label="RC TVD")
plt.ylim([0, 0.3])
plt.legend()
plt.xlabel("Circuit Depth")
qcap

Out:

Text(0.5, 0, 'Circuit Depth')

Total running time of the script: ( 0 minutes 15.576 seconds)

Gallery generated by Sphinx-Gallery