Download

Download this file as Jupyter notebook: qcap_example.ipynb.

Example: Estimating Quantum Capacity

[2]:
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.

[3]:
# 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)
[3]:
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".
QCAP
Quantum Capacity
Paulis
(0, 1, 2, 4)
Key:
  • labels: (0, 1, 2, 4)
  • protocol: QCAP
  • twirl: Paulis on [0, 1, 2, 4]
${e}_{IU}$
The inferred upper bound on the process infidelity of a circuit if it were run under RC.
1.9e-02 (1.2e-03)
0.019360296651667386, 0.0012499224583032563

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

[4]:
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.

[5]:
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.

[6]:
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)

sim.run(random_circuits, 1000)

Finally, we collect and plot the data to show that the probability of an error is below the probability predicted using QCAP.

Note that the probability is often smaller than the QCAP bound, because QCAP is predicting the probability of an error in the circuit, whereas we can only measure the probability that an error affects the state.

For example, a phase error does not contribute to the probability of an error if the system is in a computational basis state since the error does not affect the state.

[7]:
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.title("Probability of error for randomly compiled circuits")
plt.xlabel("Circuit depth")
plt.ylabel("Probability of an error")
legend = plt.legend()
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
/tmp/ipykernel_226737/692689002.py in <module>
      6
      7     # compute the QCAP bound for this circuit
----> 8     qcaps[idx, :] = tq.qcap_bound(bare_circuit, qcap_fit).e_IU[1:]
      9
     10     # compute the TVD from the RC results to the ideal bitstring distribution

~/workspace/release trueq/trueq/protocols.py in qcap_bound(circuit, fit_or_circuits)
   1074
   1075     cycle_count = defaultdict(int)
-> 1076     for cycle in tqc.Compiler([tqc.MarkCycles(marker=1)]).compile(circuit):
   1077         if cycle.marker != 0 and cycle.n_prep == 0 and cycle.n_meas == 0:
   1078             cycle_count[(cycle,)] += 1

~/workspace/release trueq/trueq/compilation/compiler.py in compile(self, circ)
    176         for backend, passes in self._grouped_passes:
    177             if backend:
--> 178                 collect = backend_compiler.compile(collect, passes)
    179             else:
    180                 for p in passes:

RuntimeError: cannot recompile a circuit that has results.

Download

Download this file as Jupyter notebook: qcap_example.ipynb.