其他
深度全面解读量子计算机性能衡量标准——Quantum Volume
在IBM关于量子体积的论文(题目见后面的参考文献1)中,
qubit_lists = [[0,1,3,5]]
ntrials = 50
qv_circs, qv_circs_nomeas = qv.qv_circuits(qubit_lists, ntrials)
def qv_circuits(qubit_lists=None, ntrials=1,
qr=None, cr=None):
"""
Return a list of square quantum volume circuits (depth=width)
The qubit_lists is specified as a list of qubit lists. For each
set of qubits, circuits the depth as the number of qubits in the list
are generated
Args:
qubit_lists: list of list of qubits to apply qv circuits to. Assume
the list is ordered in increasing number of qubits
ntrials: number of random iterations
qr: quantum register to act on (if None one is created)
cr: classical register to measure to (if None one is created)
Returns:
qv_circs: list of lists of circuits for the qv sequences
(separate list for each trial)
qv_circs_nomeas: same as above with no measurements for the ideal
simulation
"""
circuits = [[] for e in range(ntrials)]
circuits_nomeas = [[] for e in range(ntrials)]
# get the largest qubit number out of all the lists (for setting the
# register)
depth_list = [len(l) for l in qubit_lists]
# go through for each trial
for trial in range(ntrials):
# go through for each depth in the depth list
for depthidx, depth in enumerate(depth_list):
n_q_max = np.max(qubit_lists[depthidx])
qr = qiskit.QuantumRegister(int(n_q_max+1), 'qr')
qr2 = qiskit.QuantumRegister(int(depth), 'qr')
cr = qiskit.ClassicalRegister(int(depth), 'cr')
qc = qiskit.QuantumCircuit(qr, cr)
qc2 = qiskit.QuantumCircuit(qr2, cr)
qc.name = 'qv_depth_%d_trial_%d' % (depth, trial)
qc2.name = qc.name
# build the circuit
for _ in range(depth):
# Generate uniformly random permutation Pj of [0...n-1]
perm = np.random.permutation(depth)
# For each pair p in Pj, generate Haar random SU(4)
for k in range(int(np.floor(depth/2))):
U = random_unitary(4)
pair = int(perm[2*k]), int(perm[2*k+1])
qc.append(U, [qr[qubit_lists[depthidx][pair[0]]],
qr[qubit_lists[depthidx][pair[1]]]])
qc2.append(U, [qr2[pair[0]],
qr2[pair[1]]])
# append an id to all the qubits in the ideal circuits
# to prevent a truncation error in the statevector
# simulators
qc2.u1(0, qr2)
circuits_nomeas[trial].append(qc2)
# add measurement
for qind, qubit in enumerate(qubit_lists[depthidx]):
qc.measure(qr[qubit], cr[qind])
circuits[trial].append(qc)
return circuits, circuits_nomeas
perm = np.random.permutation(depth)
接下来随机产生一个unitary矩阵U,从perm中选取两个下标对2×k,2×k+1。
qv_circs_nomeas[0] = qiskit.compiler.transpile(qv_circs_nomeas[0], basis_gates=['u1','u2','u3','cx'])
在生成一个具体的SU(4)时,即生成一个矩阵,其具体的代码实现为:
z = 1/math.sqrt(2)*(random_state.normal(size=(dim, dim)) +
1j*random_state.normal(size=(dim, dim)))
q, r = scipy.linalg.qr(z)
d = r.diagonal()
q *= d/abs(d)
return q
array([[ 0.48314207-0.74685063j, -0.32001204+0.28858998j,
0.31048735-1.36176688j, -0.22157554+1.16425953j],
[-0.22952827-0.34015267j, 0.47746433+1.04415471j,
-0.59934698-0.23617052j, -1.11649142-0.41669992j],
[-0.53802896-0.82990912j, -1.21562382+0.63495078j,
0.45721007+0.7721644j , -0.5187136 -1.01859104j],
[ 0.22413704-0.40779265j, 1.71092645-0.14994469j,
-0.15958734+0.91498815j, -0.13092838-0.97944035j]])
def _heavy_strings(self, ideal_distribution, ideal_median):
"""Return the set of heavy output strings.
ideal_distribution = dict of ideal output distribution
where keys are bit strings (as strings) and values are
probabilities of observing those strings
ideal_mean = median probability across all outputs
Return the set of heavy output strings, i.e. those strings
whose ideal probability of occurrence exceeds the median.
"""
return list(filter(lambda x: ideal_distribution[x] > ideal_median,
list(ideal_distribution.keys())))
def calc_statistics(self):
"""
Convert the heavy outputs in the different trials into mean and error
for plotting
Here we assume the error is due to a binomial distribution
"""
self._ydata = np.zeros([4, len(self._depths)], dtype=float)
exp_vals = np.zeros(self._ntrials, dtype=float)
ideal_vals = np.zeros(self._ntrials, dtype=float)
for depthidx, depth in enumerate(self._depths):
exp_shots = 0
for trialidx in range(self._ntrials):
cname = 'qv_depth_%d_trial_%d' % (depth, trialidx)
exp_vals[trialidx] = self._heavy_output_counts[cname]
exp_shots += self._circ_shots[cname]
ideal_vals[trialidx] = self._heavy_output_prob_ideal[cname]
self._ydata[0][depthidx] = np.sum(exp_vals)/np.sum(exp_shots)
self._ydata[1][depthidx] = (self._ydata[0][depthidx] *
(1.0-self._ydata[0][depthidx])
/ self._ntrials)**0.5
self._ydata[2][depthidx] = np.mean(ideal_vals)
self._ydata[3][depthidx] = (self._ydata[2][depthidx] *
(1.0-self._ydata[2][depthidx])
/ self._ntrials)**0.5
def qv_success(self):
"""Return whether each depth was successful (>2/3 with confidence
greater than 97.5) and the confidence
Returns:
List of lenth depth with eact element a 3 list with
- success True/False
- confidence
"""
success_list = []
for depth_ind, _ in enumerate(self._depths):
success_list.append([False, 0.0])
hmean = self._ydata[0][depth_ind]
if hmean > 2/3:
cfd = 0.5 * (1 +
math.erf((hmean - 2/3)
/ (1e-10 +
self._ydata[1][depth_ind])/2**0.5))
success_list[-1][1] = cfd
if cfd > 0.975:
success_list[-1][0] = True
return success_list
#Import general libraries (needed for functions)
import numpy as np
import matplotlib.pyplot as plt
from IPython import display
#Import Qiskit classes classes
import qiskit
from qiskit.providers.aer.noise import NoiseModel
from qiskit.providers.aer.noise.errors.standard_errors import depolarizing_error, thermal_relaxation_error
#Import the qv function.
import qiskit.ignis.verification.quantum_volume as qv
#Qubit list
qubit_lists = [[0,1,3,5]]
ntrials = 20
qv_circs, qv_circs_nomeas = qv.qv_circuits(qubit_lists, ntrials)
#pass the first trial of the nomeas through the transpiler to illustrate the circuit
qv_circs_nomeas[0] = qiskit.compiler.transpile(qv_circs_nomeas[0], basis_gates=['u1','u2','u3','cx'])
print(qv_circs[0][0].qasm())
print("this is the transpiled circuit")
print(qv_circs_nomeas[0][0])
#The Unitary is an identity (with a global phase)
backend = qiskit.Aer.get_backend('statevector_simulator')
ideal_results = []
for trial in range(ntrials):
print('Simulating trial %d'%trial)
ideal_results.append(qiskit.execute(qv_circs_nomeas[trial], backend=backend, optimization_level=0).result())
qv_fitter = qv.QVFitter(qubit_lists=qubit_lists)
qv_fitter.add_statevectors(ideal_results)
noise_model = NoiseModel()
p1Q = 0.2
p2Q = 0.2
noise_model.add_all_qubit_quantum_error(depolarizing_error(p1Q, 1), 'u2')
noise_model.add_all_qubit_quantum_error(depolarizing_error(2*p1Q, 1), 'u3')
noise_model.add_all_qubit_quantum_error(depolarizing_error(p2Q, 2), 'cx')
#noise_model = None
print(qv_circs_nomeas[0][0])
backend = qiskit.Aer.get_backend('qasm_simulator')
basis_gates = ['u1','u2','u3','cx'] # use U,CX for now
shots = 1024
exp_results = []
for trial in range(ntrials):
print('Running trial %d'%trial)
exp_results.append(qiskit.execute(qv_circs[trial], basis_gates=basis_gates, backend=backend, noise_model=noise_model, backend_options={'max_parallel_experiments': 0}).result())
qv_fitter.add_data(exp_results)
plt.figure(figsize=(10, 6))
ax = plt.gca()
# Plot the essence by calling plot_rb_data
qv_fitter.plot_qv_data(ax=ax, show_plt=False)
# Add title and label
ax.set_title('Quantum Volume for up to %d Qubits \n and %d Trials'%(len(qubit_lists[-1]), ntrials), fontsize=18)
#plt.show()
qv_success_list = qv_fitter.qv_success()
qv_list = qv_fitter.ydata
for qidx, qubit_list in enumerate(qubit_lists):
if qv_list[0][qidx]>2/3:
if qv_success_list[qidx][0]:
print("Width/depth %d greater than 2/3 (%f) with confidence %f (successful). Quantum volume %d"%
(len(qubit_list),qv_list[0][qidx],qv_success_list[qidx][1],qv_fitter.quantum_volume()[qidx]))
else:
print("Width/depth %d greater than 2/3 (%f) with confidence %f (unsuccessful)."%
(len(qubit_list),qv_list[0][qidx],qv_success_list[qidx][1]))
else:
print("Width/depth %d less than 2/3 (unsuccessful)."%len(qubit_list))
1. Cross A W , BishopL S , Sheldon S , et al. Validating quantum computers using randomized modelcircuits[J]. 2018.
2. Blume-Kohout R , Young K C . A volumetric framework for quantum computer benchmarks[J]. 2019.