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]:
QCAP
Quantum Capacity
|
Paulis
(0, 1, 2, 4)
|
${e}_{IU}$
The inferred upper bound on the process infidelity of a circuit if it were run under RC.
|
2.3e-02 (1.5e-03)
0.022730466004173278, 0.0014555496284154945
|
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/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.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
File ~/workspace/release trueq/trueq/compilation/compiler.py:178, in Compiler.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.