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.4e-03)
0.019158375783798753, 0.0014206998039457683

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)
Cell In [7], line 8
      5 rc_circuits = random_circuits.subset(protocol="RC", depth=depth)
      7 # compute the QCAP bound for this circuit
----> 8 qcaps[idx, :] = tq.qcap_bound(bare_circuit, qcap_fit).e_IU[1:]
     10 # compute the TVD from the RC results to the ideal bitstring distribution
     11 ideal_probs = tq.Simulator().sample(bare_circuit, float("inf"))

File ~/workspace/release trueq legacy/trueq/protocols.py:1076, in qcap_bound(circuit, fit_or_circuits)
   1073 fit = fit_or_circuits.subset(protocol="CB")
   1075 cycle_count = defaultdict(int)
-> 1076 for cycle in tqc.MarkCycles(marker=1).apply(circuit):
   1077     if cycle.marker != 0 and cycle.n_prep == 0 and cycle.n_meas == 0:
   1078         cycle_count[(cycle,)] += 1

File ~/workspace/release trueq legacy/trueq/compilation/base.py:48, in Pass.apply(self, circuit)
     46     raise CompilationError(f"input {circuit} was not an acceptable type")
     47 time = datetime.now()
---> 48 result = self._apply(circuit)
     49 dt = (datetime.now() - time).total_seconds() * 1000
     50 logger.debug(f"{type(self).__name__:>25}.apply ran in \t{dt:0.1f}ms")

File ~/workspace/release trueq legacy/trueq/compilation/common.py:224, in MarkCycles._apply(self, circuit)
    223 def _apply(self, circuit):
--> 224     return local.mark_cycles(circuit, self.marker)

RuntimeError: cannot recompile a circuit that has results.

Download

Download this file as Jupyter notebook: qcap_example.ipynb.