In [1]:
Copied!
import numpy as np
try:
import numqi
except ImportError:
%pip install numqi
import numqi
np_rng = np.random.default_rng()
import numpy as np
try:
import numqi
except ImportError:
%pip install numqi
import numqi
np_rng = np.random.default_rng()
First, we build a variational quantum circuit ansatz for searching the Quantum Error Correction Code (QECC). We are going to find the five-qubit QECC wiki/five-qubit-code.
In [2]:
Copied!
def build_circuit(num_depth, num_qubit):
prime = [x for x in range(3, num_qubit) if np.gcd(x,num_qubit)==1]
assert len(prime)>=1
prime = prime[0]
circ = numqi.sim.Circuit(default_requires_grad=True)
for _ in range(num_depth):
for x in range(num_qubit):
circ.u3(x)
tmp0 = np.mod(-np.arange(num_qubit+1), num_qubit)
for x,y in zip(tmp0[:-1],tmp0[1:]):
circ.cu3(x, y)
for x in range(num_qubit):
circ.u3(x)
tmp0 = np.mod(-np.arange(num_qubit+1)*prime, num_qubit)
for x,y in zip(tmp0[:-1],tmp0[1:]):
circ.cu3(x, y)
return circ
def build_circuit(num_depth, num_qubit):
prime = [x for x in range(3, num_qubit) if np.gcd(x,num_qubit)==1]
assert len(prime)>=1
prime = prime[0]
circ = numqi.sim.Circuit(default_requires_grad=True)
for _ in range(num_depth):
for x in range(num_qubit):
circ.u3(x)
tmp0 = np.mod(-np.arange(num_qubit+1), num_qubit)
for x,y in zip(tmp0[:-1],tmp0[1:]):
circ.cu3(x, y)
for x in range(num_qubit):
circ.u3(x)
tmp0 = np.mod(-np.arange(num_qubit+1)*prime, num_qubit)
for x,y in zip(tmp0[:-1],tmp0[1:]):
circ.cu3(x, y)
return circ
hyper-parameters for the QECC specification
In [3]:
Copied!
str_qecc = '((5,2,3))' #'((6,2,de(2)=4))'
tmp0 = numqi.qec.parse_str_qecc(str_qecc)
num_qubit = tmp0['num_qubit']
num_logical_dim = tmp0['num_logical_dim']
distance = tmp0['distance']
weight_z = tmp0['weight_z']
num_layer = 5
if weight_z is None:
error_list = numqi.qec.make_error_list(num_qubit, distance)
else:
error_list = numqi.qec.make_asymmetric_error_set(num_qubit, distance, weight_z)
str_qecc = '((5,2,3))' #'((6,2,de(2)=4))'
tmp0 = numqi.qec.parse_str_qecc(str_qecc)
num_qubit = tmp0['num_qubit']
num_logical_dim = tmp0['num_logical_dim']
distance = tmp0['distance']
weight_z = tmp0['weight_z']
num_layer = 5
if weight_z is None:
error_list = numqi.qec.make_error_list(num_qubit, distance)
else:
error_list = numqi.qec.make_asymmetric_error_set(num_qubit, distance, weight_z)
In [4]:
Copied!
circuit = build_circuit(num_layer, num_qubit)
model = numqi.qec.VarQEC(circuit, num_logical_dim, error_list, loss_type='L2')
theta_optim = numqi.optimize.minimize(model, ('uniform',0,2*np.pi), num_repeat=1, tol=1e-10, print_freq=40)
code0 = model.get_code()
theta_optim = numqi.optimize.minimize(model, ('uniform',0,2*np.pi), num_repeat=1, tol=1e-10, print_freq=40)
code1 = model.get_code()
circuit = build_circuit(num_layer, num_qubit)
model = numqi.qec.VarQEC(circuit, num_logical_dim, error_list, loss_type='L2')
theta_optim = numqi.optimize.minimize(model, ('uniform',0,2*np.pi), num_repeat=1, tol=1e-10, print_freq=40)
code0 = model.get_code()
theta_optim = numqi.optimize.minimize(model, ('uniform',0,2*np.pi), num_repeat=1, tol=1e-10, print_freq=40)
code1 = model.get_code()
[step=0][time=0.265 seconds] loss=5.408242506769042
[step=40][time=4.256 seconds] loss=0.02102619811315748
[step=80][time=4.264 seconds] loss=1.928195210638756e-05
[step=120][time=4.182 seconds] loss=1.2475577069001274e-08
[round=0] min(f)=4.69907655376263e-10, current(f)=4.69907655376263e-10
[step=0][time=0.259 seconds] loss=5.762677449346853
[step=40][time=4.271 seconds] loss=0.09300306680113371
[step=80][time=4.042 seconds] loss=0.00012287697717203795
[step=120][time=4.200 seconds] loss=2.58953964842956e-07
[round=0] min(f)=8.244937118865635e-10, current(f)=8.244937118865635e-10
Above, we run the search algorithm algorithm and obtain two QECC ((5,2,3))
. We can run an optimization algorithm to determine whether the two QECCs are equivalent.
In [5]:
Copied!
model1 = numqi.qec.QECCEqualModel(code0, code1)
tmp0 = numqi.optimize.minimize(model, 'uniform', num_repeat=1, tol=1e-10, print_freq=40)
if tmp0.fun<1e-5:
print('equivalent QECC')
model1 = numqi.qec.QECCEqualModel(code0, code1)
tmp0 = numqi.optimize.minimize(model, 'uniform', num_repeat=1, tol=1e-10, print_freq=40)
if tmp0.fun<1e-5:
print('equivalent QECC')
[step=0][time=0.181 seconds] loss=5.696396069429891
[step=40][time=4.141 seconds] loss=0.6481828457973331
[step=80][time=4.144 seconds] loss=0.03752176861134235
[step=120][time=4.281 seconds] loss=0.0006147297072568177
[step=160][time=4.254 seconds] loss=4.0960628878461124e-06
[step=200][time=4.263 seconds] loss=3.669830741699767e-08
[round=0] min(f)=1.250215173286136e-09, current(f)=1.250215173286136e-09 equivalent QECC
As expected, all ((5,2,3))
QECC are local equivalent. Besides the variational ansatz, we can also directly parametrize a unitary matrix.