SDP bounds for quantum codes¶
In arxiv-link "SDP bounds for quantum codes", author provides a hierarchical Semi-Definite Programing (SDP) to certificate the existence of quantum codes. When the hierarchy goes to infinity, those SDP becomes necessary and sufficient conditions at the cost of computational complexity. The hierarchy level $l=2$ is implemented in numqi
and below will demonstrate how to use it. As claimed in paper, the $l=2$ hierarchy is sufficient to certify the nonexistence of quantum codes $((7,1,4))$, $((8,9,3))$ and $((10,5,4))$.
import numpy as np
import matplotlib.pyplot as plt
import cvxpy
try:
import numqi
except ImportError:
%pip install numqi
import numqi
# mosek is necessary for some of the examples
try:
import mosek
USE_MOSEK = True
except ImportError:
USE_MOSEK = False
Feasibility of quantum codes¶
eq(142) is implemented in numqi.qec.is_code_feasible
to check the feasibility of quantum codes. Let's check some famous known quantum codes.
# 5-qubits code
print(numqi.qec.is_code_feasible(5, 2, 3))
True
# Steane code ((7,2,3))
print(numqi.qec.is_code_feasible(7, 2, 3))
True
/home/runner/.local/lib/python3.12/site-packages/cvxpy/problems/problem.py:1481: UserWarning: Solution may be inaccurate. Try another solver, adjusting the solver settings, or solve with verbose=True for more information. warnings.warn(
then, let's reproduce the results in the paper. The nonexistance of $((7,1,4))$
numqi.qec.is_code_feasible(7, 1, 4, solver='CLARABEL')
False
To refute the code $((8,9,3))$ and $((10,5,4))$, solver="MOSEK"
is required (other solvers would raise NumericalError
for unknown reasons).
Even with solver="MOSEK"
, some constraints have to be dropped to avoid NumericalError
. If the SDP with some constraints dropped is infeasible, then the SDP with all constraints is also infeasible. Also, dropping some constraints is also done in the paper.
if USE_MOSEK:
tmp0 = numqi.qec.is_code_feasible(8, 9, 3, solver='MOSEK', drop_constraint=[2])
print('((8,9,3)):', 'feasible' if tmp0 else 'infeasible')
tmp0 = {16, 18, 20, 22, 26, 28, 30, 32, 34, 36, 38, 40, 42, 46, 48, 50, 52, 54, 56, 58, 62, 64, 66, 68, 70, 74, 76, 78, 82}
drop_constraint = [10,11,12,13] + sorted(set(range(15,86))-tmp0)
tmp1 = numqi.qec.is_code_feasible(10, 5, 4, solver='MOSEK', drop_constraint=drop_constraint)
print('((10,5,4)):', 'feasible' if tmp1 else 'infeasible')
An famous open problem is the nonexistence of $((7,3,3))$ quantum code, however, the SDP at $l=2$ is not enough to refute it.
numqi.qec.is_code_feasible(7, 3, 3)
True
Feasible region of quantum weight enumerator¶
Those SDP can approximate the feasible region of quantum weight enumerator. Shor-Laflamme's quantum weight enumerator $A_i$ is approximated in eq(142)
$$ A_{i}\approx\gamma_{i,0}^{0,0}x_{i,0}^{0,0}. $$
It should be emphasized that $A_i$ used in numqi is defined using the following normalization factor
$$ A_{i}\left[\Pi\right]=\frac{1}{K^{2}}\sum_{\mathrm{wt}(P)=i}\mathrm{Tr}\left[\Pi P\right]\mathrm{Tr}\left[\Pi P\right] $$
where $K$ is the dimension of the code space. With the constraint given in eq(142), the feasible region of $(A_1,A_2)$ can be approximated.
Feasible region of $((7,2,3))$¶
55 variables are used in this SDP. The range of $A_1$ is given by $[0,2]$ via SDP.
cvxA1para = cvxpy.Parameter()
cvxX, cvxA, cvxB, cvxS, constraint = numqi.qec.get_code_feasible_constraint(num_qubit=7, dimK=2, distance=3)
num_variable = len({x for x in cvxX.values() if isinstance(x, cvxpy.Variable)})
print('num_variable:', num_variable)
A1min = cvxpy.Problem(cvxpy.Minimize(cvxA[1]), constraint).solve(solver='CLARABEL')
A1max = cvxpy.Problem(cvxpy.Maximize(cvxA[1]), constraint).solve(solver='CLARABEL')
print(f'A1min: {A1min}, A1max: {A1max}')
num_variable: 55
A1min: 8.134445006883162e-09, A1max: 1.9999999986225718
Then we are going to plot the feasible region of $(A_1,A_2)$ for $((7,2,3))$.
A1_list = np.linspace(0, 2, 51)
tmp0 = constraint + [cvxA[1]==cvxA1para]
prob_min = cvxpy.Problem(cvxpy.Minimize(cvxA[2]), tmp0)
prob_max = cvxpy.Problem(cvxpy.Maximize(cvxA[2]), tmp0)
z0 = []
for A1 in A1_list:
cvxA1para.value = A1
z0.append(prob_min.solve(solver='CLARABEL'))
z0.append(prob_max.solve(solver='CLARABEL'))
z0 = np.array(z0).reshape(-1,2)
fig,ax = plt.subplots(figsize=(4,9))
ax.fill_between(A1_list, z0[:,0], z0[:,1], alpha=0.5)
ax.set_xlabel('$A_1$')
ax.set_ylabel('$A_2$')
ax.grid()
Feasible region of $((6,2,3))$¶
38 variables are used in this SDP. The range of $A_1$ is given by $[0,1]$ via SDP.
cvxA1para = cvxpy.Parameter()
cvxX, cvxA, cvxB, cvxS, constraint = numqi.qec.get_code_feasible_constraint(num_qubit=6, dimK=2, distance=3)
num_variable = len({x for x in cvxX.values() if isinstance(x, cvxpy.Variable)})
print('num_variable:', num_variable)
A1min = cvxpy.Problem(cvxpy.Minimize(cvxA[1]), constraint).solve(solver='CLARABEL')
A1max = cvxpy.Problem(cvxpy.Maximize(cvxA[1]), constraint).solve(solver='CLARABEL')
print(f'A1min: {A1min}, A1max: {A1max}')
num_variable: 38
A1min: 3.6690695795021496e-09, A1max: 0.9999999995994949
A1_list = np.linspace(0, 1, 51)
tmp0 = constraint + [cvxA[1]==cvxA1para]
prob_min = cvxpy.Problem(cvxpy.Minimize(cvxA[2]), tmp0)
prob_max = cvxpy.Problem(cvxpy.Maximize(cvxA[2]), tmp0)
z0 = []
for A1 in A1_list:
cvxA1para.value = A1
z0.append(prob_min.solve(solver='CLARABEL'))
z0.append(prob_max.solve(solver='CLARABEL'))
z0 = np.array(z0).reshape(-1,2)
fig,ax = plt.subplots()
ax.fill_between(A1_list, z0[:,0], z0[:,1], alpha=0.5)
ax.set_xlabel('$A_1$')
ax.set_ylabel('$A_2$')
ax.grid()