Application of Association Schemes in Calculating and Implementing Linear Programming Bounds For Codes in SageMath
Application of Association Schemes in Calculating and Implementing Linear Programming Bounds For Codes in SageMath
Trinity 2021
Candidate Number: 1034125
Coding theory is an area of mathematics that examines the reliable and efficient
transmission of information over noisy channels. To achieve this, mathematical
constructions named codes are used. An important goal of coding theory is to study
the relationship between the length and the specification of a code, and its ability to
transmit information accurately and efficiently. This project aims to investigate how
the theory of association schemes can be applied in order to formulate bounds on
the size of codes and how these bounds can then be implemented for an open-source
library, SageMath, so that they can be used for further research in a great variety
of fields. The starting point for these is the derivation of the Linear Programming
bound, as it was put forth first by Delsarte [8]. This bound is then enhanced with
further constraints, obtaining 40 improved bounds on the size of binary constant
weight codes. Finally, we generalize the bound to other schemes, demonstrating its
application on the association scheme of Hermitian dual polar graphs.
Acknowledgements
I would like to deeply thank my supervisor Dr. Pasechnik for guiding me through
this process, facilitating my introduction to a variety of interesting fields of math-
ematics, helping me become familiar with SageMath, and kindly offering previous
unpublished work of his, in the form of both code and papers, to assist me in com-
pleting the project.
I would also like to express my gratitude towards my college tutor Professor
Živný for his continuous support throughout the years of my undergraduate degree,
going above and beyond to ensure that all of us had an all-around smooth learning
experience.
Last but not least, I want to thank my family and friends for their unfaltering
support and encouragement, always being there for me in difficult moments.
Contents
1 Introduction 1
1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Problem Statement and Related Work . . . . . . . . . . . . . . . . . 1
1.3 Project Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
3 Association Schemes 5
3.1 Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3.2 The Bose-Mesner Algebra . . . . . . . . . . . . . . . . . . . . . . . . 5
3.3 The matrices P and Q . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.4 The Linear Programming Bound . . . . . . . . . . . . . . . . . . . . 8
7 Conclusion 23
7.1 Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
7.2 Future Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
References 25
8 Appendices 27
8.1 Appendix I: Code for Binary Constant Weight Codes . . . . . . . . . 27
8.2 Appendix II: Testing for Binary Constant Weight Codes . . . . . . . 30
8.3 Appendix III: Code for Q-matrix LP Building . . . . . . . . . . . . . 33
8.4 Appendix IV: Testing Code for Q-matrix LP Building . . . . . . . . . 35
8.5 Appendix V: Hermitian dual polar graphs Q-matrix generation . . . . 36
8.6 Appendix VI: Hermitian dual polar graphs Testing . . . . . . . . . . 37
1 Introduction
1.1 Motivation
In the age of the internet, huge amounts of information are constantly being trans-
mitted around us, encoded using some sort of a coding system. The distance and
the mediums that information has to go through causes loss of information to be a
common issue. Using more technical terminology, information channels are usually
noisy. Coding theory is an area of mathematics that deals with the reliable and
efficient transmission of information over noisy channels. The constructions we use
to achieve this are called codes. An obvious criterion to judge the practicality of a
code is its size, meaning the number of distinct codewords it contains, as this depicts
the amount of information we can encode using it. Therefore, it is important to be
able to reason about bounds on the sizes of codes. This constitutes the first aim
of this project, while the second goal is to implement the bounds discussed above
in SageMath. SageMath is a free, open-source mathematics software system, which
covers a great variety of fields. Its mission is to "create a viable free open source
alternative to Magma, Maple, Mathematica and Matlab."[21]. It is built using
Python, and it allows coding in Python as well as in a language (sage) which is an
extension of Python.
The main theme of the project, which is then improved and extended, is Delsarte’s
Linear Programming Bound. First derived in P.Delsarte’s 1973 paper “An algebraic
approach to the association schemes of coding theory”[8], the connection between
association schemes and certain codes has already been used in a variety of papers,
along with numerous improvements, aiming to provide tighter bounds to the size
of codes. Two classes of such codes are the Hamming Codes and the Binary Con-
stant Weight Codes, with the corresponding association schemes being the Hamming
1
scheme and the Johnson scheme. SageMath already contained work for the former,
therefore the first problem solved by this project is the derivation and implementa-
tion of the Linear Programming bound for Binary Constant Weight Codes. The first
question that immediately arises is where else this bound could be applied. For this
reason, we provide a more generic formulation of the Linear Programming bound,
which can be used to calculate bounds on Q-polynomial association schemes. We
proceed by employing this generic function to the Q-polynomial association scheme
of Hermitian dual polar graphs.
2
2 Coding Theory Foundations
Before presenting the main results of this project, it is important to provide some
basic definitions. A field is a set on which addition and multiplication behave
similarly to how they behave for rational and real numbers. Denote Fq to be a
field, the elements of which create an alphabet of size q = pk , for p a prime number.
We then define a word to be an element v ∈ Fnq , where n is a fixed natural number.
A code C is a subset of Fnq . Every word v ∈ C (for come code C ⊆ Fnq ) is called a
codeword of that code. The weight of a codeword v, denoted as w(v), is the number
of nonzero entries of v. It is useful to define a distance function between any two
codewords. One of the most widely used distance functions is the Hamming distance
(dH (u, v) for some codewords u, v), which measures the number of positions in which
two words differ: dH (u, v) = |{i | ui 6= vi }|. [22]
One important property of codes is their minimum distance. We define the minimum
distance dmin (C) of a code C to be the minimum distance between any pair of
distinct codewords in C. To appreciate why this property is useful, we can consider
the transmission of a codeword v that belongs in some code C. As discussed in the
introduction, it is important for codes to be reliable, therefore any errors in their
transmission should be recognizable and we should be able to recover the original
codeword, assuming a reasonable number of transmission errors. In the case where v
is transmitted but v 0 6= v is received, we should have a method to try and reconstruct
the codeword that was intended to be sent.
A typical approach for achieving that is by using the method of Nearest Neigh-
bour decoding. In our example, the method would calculate the distances between
v 0 and all c ∈ C, and return the codeword c0 that is closest to v 0 . We can easily see
3
that the number of errors that are detectable and correctable are somehow related to
the minimum distance of the code [17]. As mentioned earlier, our goal is to establish
upper bounds on the size of codes.
We define A(n, d) to be the maximum size of a code (which is a subset of some
Fnq ) of minimum distance at least d, and A(n, d, w) to be the maximum size of such
a code with the additional property of each codeword having weight w.
Before proceeding to specific types of codes and their bounds, it is also important
to introduce the theory of association schemes and their connection with some codes.
This is what we are going to use later to derive the linear programs, which will give
us the bounds on the size of the codes.
4
3 Association Schemes
3.1 Definition
An association scheme with d classes consists of a finite set X together with a set
R of d + 1 relations R0 , R1 , ..., Rd on X with the following properties:
(i) R partitions X 2
(iii) if (x, y) ∈ Ri , then also (y, x) ∈ Ri for all x, y ∈ X and i ∈ {0, ..., d}, which is
equivalent to saying that for any Ri ∈ R the inverse relation Ri−1 also belongs
to R
(iv) For any i, j, k ∈ {0, 1, ..., d}, there exists a number pki,j = pkj,i such that for all
(x, y) ∈ Rk :
|{z ∈ X |(x, z) ∈ Ri , (z, y) ∈ Rj }| = pki,j
The numbers pki,j are called the intersection numbers of the association scheme. It
is then convenient to define the intersection matrices L0 , ...Ld which satisfy (Li )kj =
pkij . [5]
We can now rewrite the axioms of association schemes in the following way:
5
(iii) Ai = ATi , for all i ∈ {0, 1, ..., d}
We can see that the matrices Ai are linearly independent from axiom (i). To proceed,
it is useful to define the concept of an algebra over a field. An algebra is a vector
space together with a bilinear product operation (which combines elements of two
vector spaces to return an element of a third vector space, being linear in all its
arguments). Furthermore, we see that the above axioms (ii)-(iv) can generate a
commutative (since axiom (iv) and the fact that pki,j = pkj,i yield that Ai Aj = Aj Ai )
(d+1)-dimensional algebra A of symmetric matrices (from axiom (iii)) with constant
diagonal, since A0 ’s diagonal consists only of 1s, and all other Ai s’ diagonals consist
only of 0s. This particular algebra was first studied by Bose and Mesner and it is
called the Bose-Mesner algebra. [5]
Since the Ai matrices commute, they can be diagonalized simultaneously [9],
that is, there exists a matrix S such that for each Ai ∈ A, S −1 Ai S is a diagonal
matrix. By the spectral theorem of linear algebra[15], A has a unique basis of
minimal idempotents E0 , ..., Ed , which satisfy:
d
X
Ei Ej = δij Ei , Ei = I
i=0
Let P and n1 Q be the matrices which relate the two bases for A as follows:
d d
X 1X
Aj = Pij Ei , Ej = Qij Ai
i=0
n i=0
1
A = EP, E = AQ
n
6
Then:
P Q = (E −1 A)(nA−1 E) = nI
and similarly:
QP = nI
Xd d
X d
X
Aj Ei = ( Pij Ei )Ei = Pkj Ek Ei = Pkj δki Ei = Pij Ei
i=0 k=0 k=0
which shows that Pij are the eigenvalues of Aj and that the columns of Ei are
the corresponding eigenvectors. We can compute the matrices P and Q from the
intersection numbers of the scheme. To achieve this, we first show another property
of the above-defined P matrix as follows:
We know that Aj Ak = di=0 pki,j Ak . Using the definition of Pij we then have:
P
d
X Xd d
X
Aj Ak = plj,k Al ⇔ Aj Ak Ei = ( l
pj,k Al )Ei ⇔ Aj Pik Ei = plj,k Al Ei
l=0 l=0 l=0
d
X d
X
⇔ Pik Aj Ei = plj,k Pil Ei ⇔ Pij Pik = plj,k Pil
l=0 l=0
We can now show that the intersection matrix Lj has eigenvalues Pij :
d X
X d d X
X d
(P Lj P −1 )im = Pil (Lj )lk (P −1 )km = Pil plj,k (P −1 )km =
k=0 l=0 k=0 l=0
d X
X d d
X d
X
−1 −
= ( l
Pil pj,k )(P )km = Pij Pik (P 1)km = Pij Pik (P −1 )km = δim Pij
k=0 l=0 k=0 k=0
This means that P Lj P −1 = diag(P0j , ..., Pdj ), so the Pij are the eigenvalues of Lj .
Hence, we can easily now compute P and Q = n1 P −1 . We also notice that the rows
of P are left eigenvectors and the columns of Q are right eigenvectors.
7
3.4 The Linear Programming Bound
• ai ≥ 0 for all i
We will now proceed to apply this to a specific class of codes, that of Binary Constant
Weight Codes.
8
4 Bound for Binary Constant Weight Codes
An (n, d) binary code is a subset of F2n , where F = {0, 1}, whose codewords have
minimum distance d. An (n, d, w) constant weight binary code is a code satisfying
the above, with the additional property that all its codewords have the same weight
(w), which in our case means that each codeword has w ones and n − w zeros. We
are looking to calculate bounds on the maximum size of the code, which we denote
as A(n, d, w).
for all x, y ∈ X .[12] Now we can define the relations for the association scheme as
R = {R0 , R1 , ..., Rn } where:
Ri = {(x, y) ∈ X 2 | dJ (x, y) = i}
w n−w
vi =
i i
9
4.3 Properties of Binary Constant Weight Codes
Before proceeding to build the LP, it is convenient to introduce some useful proper-
ties of Binary Constant Weight Codes [16], which we can then turn into constraints
for our LP, to achieve a tighter bound:
(iii) A(n, 2, w) = n
w
We can then always assume (using (i) and (iii)) that d is even and d ≥ 4. Further-
more, using (ii),(iv),(v), we can assume that d < 2w ≤ n. [13]
To apply the theory discussed in section 4, we have to find formulas for the eigen-
matrices P and Q. These can be computed using a result in combinatorics that
produces the Eberlein polynomial (or dual Hahn polynomial), which is defined in
the following way:
k
X x w−x n−w−x
j
Ek (x) = (−1)
j=0
j k−j k−j
where
n n n − 2i + 1 n
µi = − =
i i−1 n−i+1 i
10
We can now construct the Linear Program as described in the last section. This
will be similar to what was derived in section 4, with the additional constraints of
section 5.3. The result is the following LP:
n
X
maximize Ai
i=0
subject to A0 = 1
Aj = 0 for j s.t. 0 < j < d
Aj = 0 for j s.t. 2w < j
Aj = 0 for odd j
SageMath already contained code for calculating Delsarte bounds for Hamming
codes [20], so it was clear where in the codebase the new additions belonged, as
11
well as what the coding conventions and paradigms followed by SageMath were.
The first function to implement was the one defining the Eberlein polynomials:
def eberlein(n,k,l,x):
from sage.arith.all import binomial
from sage.arith.srange import srange
return sum([(-1)**j*binomial(x,j)*binomial(n-x,k-j)
*binomial(l-n-x,k-j) for j in srange(0,k+1)])
Of course, the above is a simplified version of the actual code, which includes
sanity checks on the values of the arguments as well as many lines of documentation,
which contain examples, tests and references justifying the correctness of what is
being implemented. Notice that we are using other tools from SageMath at the same
time, such as binomial and srange, in order to achieve consistency and potentially
more efficient code.
We are now ready to build the linear program, before we use a prebuilt solver to
get a solution. The version of the LP that we implement is based on Delsarte’s theory
as we discussed, and a simplification of the formulation to make it more suitable for
coding by Kang [13]. We build the LP using the following helper function:
def _delsarte_cwc_LP_building(n,d,w,solver,isinteger):
from sage.numerical.mip import MixedIntegerLinearProgram
from sage.arith.all import binomial
p = MixedIntegerLinearProgram(maximization=True, solver=solver)
A = p.new_variable(integer=isinteger, nonnegative=True)
p.set_objective(sum([A[2*r] for r in range(d//2,w+1)])+1)
def _q(k,i):
v_i = binomial(w,i) * binomial(n-w,i)
return eberlein(w,i,n,k)/v_i
for k in range(1,w+1):
p.add_constraint(sum([A[2*i]*_q(k,i) for i in range(d//2,w+1)]),
12
min=-1)
return A, p
Having implemented the code to build the Linear Program, we make use of Sage-
Math’s sophisticated LP solvers to calculate the bounds. To evaluate the outcome
of our approach, we compare our results to the best previously known upper bounds.
To this end, the tables by A.E.Brouwer [3] proved very helpful. In order to scrape
and clean the data from the tables (as they contained both lower and upper bounds
as well some references to the papers establishing them), a Python script was writ-
ten, which can be found in Appendix II. Having extracted the data, we can create
a script that automatically tests our approach, taking advantage of the fact that it
is possible to import our local version of SageMath (including the above changes)
in any Python file by running a sage shell built using the local version of Sage. The
testing module iterates over possible values for n and w and in the cases where the
bounds are defined, it checks how the new derived bound compares to the previ-
ously known one, keeping track of the number of better, equal, and worse bounds
achieved, as well as of the cases where the new bound is an improvement. Run-
13
ning this showed that we match the best known bound in 40 cases, and we get an
overestimation in the remaining 32 cases.
14
n d w previous improved
17 4 3 44 43
23 4 3 83 81
20 6 9 1363 1335
20 6 10 1420 1413
21 6 10 2685 2604
23 10 10 116 115
23 10 11 135 134
24 10 10 170 168
24 10 11 222 217
25 10 9 157 154
25 10 10 262 261
25 10 11 379 377
26 10 9 213 208
28 10 12 1977 1967
28 10 13 2438 2425
28 10 14 2628 2626
29 10 12 3091 3981
27 12 12 139 138
27 12 13 155 154
28 12 11 147 146
28 12 12 198 196
29 12 11 197 193
29 12 12 298 296
29 12 14 492 486
30 12 10 159 157
30 12 12 492 486
31 12 10 229 194
31 12 11 415 375
31 12 12 679 678
32 12 10 300 243
32 12 11 573 568
32 12 14 2140 2133
32 12 15 2641 2496
32 12 16 2870 2642
29 14 12 47 46
31 14 14 167 165
31 14 15 183 182
32 14 13 183 181
32 14 14 233 232
32 14 15 277 274
15
5 P- and Q- Polynomial Association Schemes
Next, we look to generalize these bounds to other types of codes. To do this, we will
consider a specific class of association schemes, namely the P − and Q− polynomial
association schemes.
d
1X k
Ei ◦ Ej = q Ek
n k=0 ij
where the numbers qijk are called the Krein parameters. An important property of
the Krein parameters is that for all i, j, k ∈ {0, ..., d} they satisfy qijk ≥ 0. This
shows a dual behaviour between on the one side ordinary multiplication, the inter-
section numbers pkij and the matrices Ai and P and on the other side Hadamard
multiplication, the Krein parameters qijk and the matrices Ei and Q. [5]
We are now able to define P − and Q− polynomial association schemes as we
discussed earlier.
5.2 Definition
Association schemes in which the relations Ri represent two elements having distance
i are called metric. Metric schemes are characterized by the fact that pkij is zero
whenever one of i, j, k is larger than the sum of the other two (we can think of this
as a form of a triangle inequality), and nonzero in the case where i = j + k. As we
would expect, a cometric scheme is defined dually, by qijk = 0 when i > j + k and
i
qjk > 0 when i = j + k.
An association scheme is called P −polynomial if there exist polynomials fk of
degree k with real coefficients, and real numbers zi such that Pik = fk (zi ). Dually,
16
an association scheme is called Q−polynomial when the above holds for Q instead
of P .
There is an interesting relation between metric association schemes and a no-
tion that we will introduce in section 6.2, that of distance-regular graphs. Namely,
both represent the same object. An important theorem which can be found in [5]
(Theorem 11.6.1) states that an association scheme is metric (resp. cometric), and
thus can be thought of as a distance-regular graph, if and only if it is P -polynomial
(resp. Q-polynomial).
def _delsarte_Q_LP_building(q,d,solver,isinteger):
from sage.numerical.mip import MixedIntegerLinearProgram
n, _ = q.dimensions()
p = MixedIntegerLinearProgram(maximization=True,solver=solver)
A = p.new_variable(integer=isinteger,nonnegative=True)
p.set_objective(sum([A[i] for i in range(n)]))
p.add_constraint(A[0]==1)
try:
for i in range(1,d):
p.add_constraint(A[i]==0)
17
except:
for i in d:
p.add_constraint(A[i]==0)
for k in range(n):
p.add_constraint(sum([q[k][i]*A[i] for i in range(n)]),min=0)
return A, p
An additional feature of the above code is that it allows for the option of having
a list of indices such that A[i]s will be set to 0 in the LP, which proves to be useful
for some association schemes. We use the try-except block to achieve this form of
polymorphism (d can be either an integer - the minimum distance - or a list of
integers), which is consistent with Python’s conventions.
Indeed, we verify that this procedure works by testing it against the ones already
implemented in SageMath, the one for the Hamming scheme [20] and the one we
just derived for the Johnson scheme. The code producing the Q matrices for both
schemes can be found in Appendix IV.
In the next chapter, we are going to show how this function can be applied
to other problems that have the structure of an association scheme, such as the
Hermitian Dual Polar graphs.
18
6 Application to Hermitian Dual Polar Graphs
We begin by defining some basic terms that are essential to establishing what Her-
mitian Dual Polar Graphs are.
6.1 Definitions
Let V (n, q) denote the vector space of dimension n over the field Fq . Consider also
a Hermitian form, which we can think of as an inner product, defined as a function
h : V × V → C such that h(w, z) = h(z, w). A subspace U of V (n, q) is called
totally isotropic if the restriction to U of the Hermitian form above is identically
zero, meaning that h(z, w) = 0 for all z, w ∈ U . Then, a Hermitian polar space P is
the collection of all totally isotropic subspaces of V (n, q). Define the Witt index d of
V (n, q) to be the dimension of the largest totally isotropic subspace of V (n, q), which
we often call the rank of P. All maximal isotropic subspaces are called generators
of the polar space. We can now define the Hermitian Dual Polar Graph on P to
be the graph whose vertices are the generators of P and where two generators are
adjacent if and only if their intersection has dimension d − 1. [1]
We are looking for bounds on the constant distance codes of generators on Hermitian
polar spaces of type H(2d−1, q 2 ). This means that the vector space in the definition
of the specific Hermitian polar space has dimension 2d − 1 and the size of the field is
q 2 , as it also includes complex numbers. For generators of Hermitian polar spaces,
constant distance codes are sets of subspaces which pairwise intersect in codimension
i (so in dimension d − i where d is the Witt index of the polar space). We define
partial spreads as constant distance codes with i = d. [11] Let X be the set of all
the above Hermitian forms and define Ri relations as follows:
19
Then, Y = (X, {Ri }0≤i≤d ) is a (P and Q)-polynomial association scheme.[2] The
following are the intersection numbers of the distance-regular 1
graph Γ = (X, R1 ):
q 2d − q 2i
bi = bi (d, q) =
q+1
q i−1 (q i − (−1)i )
ci = ci (d, q) =
q+1
q 2i − q i−1 (q i − (−1)i ) − 1
ai = ai (d, q) =
q+1
bj
bj |Vj | = cj+1 |Vj+1 | ⇒ bj kj = cj+1 kj+1 ⇒ kj+1 = kj
cj+1
Note that k0 = 1, since only one vertex has distance 0 from v (itself), thus we can
compute kj+1 recursively, as we already know the bj and cj+1 . This is implemented
in the function Hdpgk (returning the value of k for Hermitian dual polar graph)
below:
def Hdpgk(p,f,d,j):
q = p^f
1
A connected graph Γ is called distance-regular if it is regular of valency (degree of vertices)
k and for any two points γ, δ ∈ Γ at distance i = d(γ, δ), there are precisely ci neighbours of δ
in Γi−1 (γ) and bi neighbours of δ in Γi+1 (γ). The array of integers ({b0 , b1 , ..., bd−1 ; c1 , c2 , ..., cd },
where d is the diameter of Γ) characterizing a distance-regular graph is known as its intersection
array.[4]
20
def b(i):
return q^(2*i)*(q^(2*(d-i))-1)/(q+1)
def c(i):
return q^(i-1)*(q^i-(-1)^i)/(q+1)
if j==0: return 1
return b(j-1)*Hdpgk(p,f,d,j-1)/c(j)
In F.Ihringer’s paper "A new upper bound for constant distance codes of generators
on Hermitian polar spaces of type H(2d − 1, q 2 )"[10], a table of bounds on the
maximum size of partial spreads in H(2d − 1, q 2 ) is given, depending on the values
of d (where d is even) and q. As discussed in the paper, it is not known whether
these bounds are sharp or not, so it would be worth testing our approach in deriving
them. We can then test the generalized procedure that was defined in section 5.3
for all Q-polynomial schemes, using as input the matrix Q derived in the previous
section. The code for testing this and comparing with the best known bounds for
each case can be found in Appendix VI.
All the bounds that were produced by the code were less tight than the best
known ones discussed in [10]. However, this still verifies that our construction is
correct and indeed provides an upper bound in all cases. This could be revisited
when further improvements to the bound on association schemes are implemented,
21
as we will discuss later in the future work section of the conclusion.
Similarly to the case of binary constant weight codes, in which we only got
improvements in a limited number of cases, here also we see that there are other
approaches that outperform our method. This is logical, because most of these
approaches further exploit the structure of the specific problem, whereas ours applies
a generic method using only the Q-polynomiality of the schemes. However, the
ability of our method to generalize proves to be very useful and worth exploring,
since a potential breakthrough in bounds for Q-polynomial association schemes could
instantly lead to improvements on a variety of problems.
22
7 Conclusion
7.1 Evaluation
This project served two purposes; firstly, providing rigorous mathematical proofs
to derive the bounds, and, secondly, discussing their implementation for SageMath
and the results of their testing. To this end, we formulated the Linear Programming
Bound, using properties of the structure of Association Schemes, around which the
core of the project revolved.
This bound was first implemented specifically for the case of Binary Constant
Weight Codes, for which the Integer Linear Program produced improvements to the
previously best known bounds in 40 cases, using the fact that the variables of the
objective function all represent integers. Consequently, we generalized the function
to be applicable to all types of Q-polynomial association schemes, which, after being
deployed in SageMath - an open-source framework-, will facilitate research in a vari-
ety of topics. Even in the specific project, other than the field of coding theory, there
were applications to graph theory, information theory, geometry, and combinatorics.
There is even an interesting instance of a quantum information theory problem to
which similar bounds can be applied, discussed in [14].
Finally, we demonstrated how this generalized code could be applied to a different
setting, by considering the association scheme corresponding to Hermitian Dual
Polar Graphs. After deriving the Q-matrix for these, we compared the upper bounds
of our implementation to the best known ones, which unfortunately in this case did
not show any improvements, but still verified the fact that the upper bounds are
correct (they do indeed provide a close overestimation).
An obvious way to apply the results of this project would be to use the generic
function on other Q-polynomial association schemes in the literature, similarly to
23
what we did for Hermitian dual polar graphs. An example of that could be partial
ovoids [7], such as the Ree-Tits octagon O(2t ) [11]. The book "Algebraic Combi-
natorics I"[2] provides an extensive list of other examples of P - and Q- polynomial
association schemes in chapter 3.6.
Another opportunity for extension of this project would be in deriving even
tighter bounds. There has already been work on that, with an example of such an
improvement being the use of Semidefinite Programming (cf. Schrijver’s paper "New
Code Upper Bounds From the Terwillger Algebra and Semidefinite Programming"[19]).
Clearly, an improvement on that could yield tighter bounds in all of the above-
discussed association schemes. Furthermore, an improvement to the more specific
bound for binary constant weight codes is discussed in the paper "Delsarte’s Linear
Programming Bound for Constant-Weight Codes"[13] in section III.B, and another
one was given by Polak in "Semidefinite programming bounds for constant weight
codes" [18], based on the work of Schrijver.
24
References
[1] R. F. Bailey and P. Spiga. Metric dimension of dual polar graphs, 2017.
[3] A. E. Brouwer. Bounds for binary constant weight codes, Mar 2021.
[10] F. Ihringer. A new upper bound for constant distance codes of genera-
tors on Hermitian polar spaces of type H(2d − 1, q 2 ). Journal of Geometry,
105(3):457–464, 2014.
[11] F. Ihringer, P. Sin, and Q. Xiang. New bounds for partial spreads of H(2d−1, q 2 )
and partial ovoids of the ree–tits octagon. Journal of Combinatorial Theory,
Series A, 153:46–53, 2018.
[12] S. Johnson. Upper bounds for constant weight error correcting codes. Discrete
Mathematics, 3(1):109–124, 1972.
25
[13] B. G. Kang, H. K. Kim, and P. T. Toan. Delsarte’s linear programming
bound for constant-weight codes. IEEE Transactions on Information Theory,
58(9):5956–5962, 2012.
[17] S. McKinley. The hamming codes and delsarte’s linear programming bound.
Master’s thesis, Portland State University, May 2003.
[18] S. Polak. Semidefinite Programming Bounds for Constant Weight Codes. IEEE
Transactions on Information Theory, 65(1):28–38, 2019.
[19] A. Schrijver. New code upper bounds from the terwilliger algebra and
semidefinite programming. IEEE Transactions on Information Theory,
51(8):2859–2866, 2005.
26
8 Appendices
27
if 2*w>n:
return eberlein(n,n-w,k,u)
return sum([(-1)**j*binomial(u,j)*binomial(w-u,k-j)
*binomial(n-w-u,k-j) for j in srange(0,k+1)])
def _delsarte_cwc_LP_building(n, d, w, solver, isinteger):
"""
LP builder for Delsarte's LP for constant weight codes, used in
delsarte_bound_constant_weight_code; not exported.
INPUT:
- ``n`` -- the code length
- ``w`` -- the weight of the code
- ``d`` -- the (lower bound on) minimal distance of the code
- ``solver`` -- the LP/ILP solver to be used. Defaults to
``PPL``. It is arbitrary precision, thus there will be no
rounding errors. With other solvers (see
:class:`MixedIntegerLinearProgram` for the list), you are on
your own!
- ``isinteger`` -- if ``True``, uses an integer programming solver
(ILP), rather that an LP solver. Can be very slow if set to
``True``.
"""
from sage.numerical.mip import MixedIntegerLinearProgram
from sage.arith.all import binomial
p = MixedIntegerLinearProgram(maximization=True, solver=solver)
A = p.new_variable(integer=isinteger, nonnegative=True)
p.set_objective(sum([A[2*r] for r in range(d//2,w+1)])+1)
def _q(k,i):
v_i = binomial(w,i)*binomial(n-w,i)
28
return eberlein(n,w,i,k)/v_i
for k in range(1,w+1):
p.add_constraint(sum([A[2*i]*_q(k,i) for i in range(d//2,w+1)]),min=-1)
return A, p
def delsarte_bound_constant_weight_code(n, d, w, return_data=False,
solver="PPL", isinteger=False):
"""
Find the Delsarte bound on a constant weight code of weight ``w``,
length ``n``, lower bound on minimal distance ``d``
INPUT:
- ``n`` -- the code length
- ``d`` -- the (lower bound on) minimal distance of the code
- ``w`` -- the weight of the code
- ``return_data`` -- if ``True``, return a triple
``(W,LP,bound)``, where ``W`` is a weights vector, and ``LP``
the Delsarte upper bound LP; both of them are Sage LP data.
``W`` need not be a weight distribution of a code.
- ``solver`` -- the LP/ILP solver to be used. Defaults to
``PPL``. It is arbitrary precision, thus there will be no
rounding errors. With other solvers (see
:class:`MixedIntegerLinearProgram` for the list), you are on
your own!
- ``isinteger`` -- if ``True``, uses an integer programming solver
(ILP), rather that an LP solver. Can be very slow if set to
``True``.
"""
from sage.numerical.mip import MIPSolverException
if d<4:
29
raise ValueError("Violated constraint d>=4 for
Binary Constant Weight Codes")
if d>=2*w or 2*w>n:
raise ValueError("Violated constraint d<2w<=n for
Binary Constant Weight Codes")
# minimum distance is even => if there is an odd lower bound on d we can
# increase it by 1
if d%2: d+=1
A, p = _delsarte_cwc_LP_building(n, d, w, solver, isinteger)
try:
bd = p.solve()
except MIPSolverException as exc:
print("Solver exception: {}".format(exc))
if return_data:
return A,p,False
return False
if return_data:
return A,p,bd
else:
return int(bd)
Code for scraping Brouwer’s page to get the bounds into csv files in order to automate
testing:
import pandas as pd
import numpy as np
import json
tables = pd.read_html('https://www.win.tue.nl/~aeb/codes/Andw.html#d4')
30
d_tables = {
4:tables[1], 6:tables[4], 8:tables[8], 10:tables[15],
12:tables[19], 14:tables[23], 16:tables[26],
18:tables[28]
}
d_vals = [4,6,8,10,12,14,16,18]
def format_data(x):
# check for nan
if pd.isna(x):
return None
# get upper bounds only (eliminate -)
if '-' in str(x):
x = x[(x.index('-')+1):]
# get rid of references etc
if not str(x).isdigit():
i = 0
while i<len(str(x)):
if not str(x)[i].isdigit():
x = str(x)[:i]
break
i += 1
# cases where only lower bound given
if x == '': return None
return int(x)
# make first col index, drop last row, apply format_data, create csv
for key in d_vals:
d_tables[key] = d_tables[key].set_index('n\w')[:-1].applymap(format_data)
d_tables[key].to_csv(f'd{key}.csv')
31
Code for testing (both LP and ILP):
32
if exp<b:
print('IMP')
leq+=1
improved.append(f'A({n},{d},{w})={exp} --- was {b}')
elif exp>b:geq+=1
else:eq+=1
print('RESULTS')
print(f'leq={leq},eq={eq},geq={geq}')
print('******IMPROVED*****')
for imp in improved:print(imp)
if __name__=="__main__":
cwc_tests()
def _delsarte_Q_LP_building(q,d,solver,isinteger):
from sage.numerical.mip import MixedIntegerLinearProgram
n, _ = q.dimensions() # Q is a square matrix
p = MixedIntegerLinearProgram(maximization=True, solver=solver)
A = p.new_variable(integer=isinteger, nonnegative=True)
p.set_objective(sum([A[i] for i in range(n)]))
p.add_constraint(A[0]==1)
try:
for i in range(1,d):
p.add_constraint(A[i]==0)
except:
for i in d:
p.add_constraint(A[i]==0)
for k in range(1,n):
33
p.add_constraint(sum([q[k][i]*A[i] for i in range(n)]),min=0)
return A, p
34
a sage Matrix()")
A, p = _delsarte_Q_LP_building(q, d, solver, isinteger)
try:
bd=p.solve()
except MIPSolverException as exc:
print("Solver exception: {}".format(exc))
if return_data:
return A,p,False
return False
if return_data:
return A,p,bd
else:
return bd
35
def johnson_scheme_q_matrix(n,w):
rows = []
for i in range(w+1):
row = []
for j in range(w+1):
row.append(codes.bounds.eberlein(n,w,i,j,inef=True))
rows.append(row)
p_matrix = Matrix(rows)
q_matrix = binomial(n,w)*p_matrix.inverse()
return q_matrix
eration
# (a_1,a_2,...,a_k;q)_n:=prod_{j=1}^k(a_j;q)_n
def brlist_n(q,n,*a):
def br(x): return prod([1-x*q**k for k in range(n)])
return prod([br(aj) for aj in a])
def q_hyper(q,z,a,b,ulim=oo):
s = len(a)
if s-1 == len(b):
if ulim==oo: # do a symbolic summation
var('kkk')
return sum(z**kkk*brlist_n(q,kkk,*a)/
brlist_n(q,kkk,*(b+[q])), kkk, 0, ulim)
else:
return reduce(lambda x,y: x+y, [z**k*brlist_n(q,k,*a)/
brlist_n(q,k,*(b+[q])) for k in range(ulim+1)])
# P and Q for the Hermitian dual polar graph of dimension d
36
# over the field GF(p^f)
# multiplicites - j's multiplicity, starting from 0, e=1/2
# implement [BCN] Thm 9.4.3
def Hdpgm(p,f,d,j):
q=p^(2*f)
return q^j*prod([(q^(d-t+1)-1)/(q^t-1) for t in range(1,j+1)]) * \
(1+q^(d-2*j)*p^f) * prod([(1+q^(d-i)*p^f)/(1+q^i/p^f)
for i in range(1,j+1)])/(1+q^(d-j)*p^f)
# Calculation of valencies
def Hdpgk(p,f,d,j):
q = p^f
def b(i):
return q^(2*i)*(q^(2*(d-i))-1)/(q+1)
def c(i):
return q^(i-1)*(q^i-(-1)^i)/(q+1)
if j==0: return 1
return b(j-1)*Hdpgk(p,f,d,j-1)/c(j)
# (1st ordering), returns Q-matrix for Hdpg
def Hdpg(p,f,d):
q=p^(2*f)
def ff(i,j):
return Hdpgk(p,f,d,j)*q_hyper(q,q,[q^-i,q^-j,-p^-f*q^(j-d)],
[q^-d,0],ulim=i)
return matrix(d+1,d+1,ff)
def hdpg_test():
improvements = 0
37
prime_powers = [2,3,4,5,7,8,9,11,13,16,17,19,23,25,27,29,31,32,37,41,
43,47,49,53,59,61,64,67,71,73,79,81,83,89,97,101,103,107,109,
113,121,125,127,128,131,137,139,149,151,157,163,167,169]
# tests for d = 2
d = 2
for q in prime_powers[1:]:
Q = Hdpg(q,1,2*d-1)
A,p,bd = codes.bounds.delsarte_bound_Q_matrix(Q.transpose(),2*d-1,
return_data=True,isinteger=True)
best = (q^3+q+2)/2
if bd<best: improvements += 1
print(f"q={q},d={d},new bound = {int(bd)}, best known = {best},{bd>best}")
# tests for d = 4
d = 4
for q in prime_powers:
Q = Hdpg(q,1,2*d-1)
A,p,bd = codes.bounds.delsarte_bound_Q_matrix(Q.transpose(),2*d-1,
return_data=True,isinteger=True)
best = q^(2*d-1)-q^(3*d/2)*(q^(0.5)-1)
if bd<best: improvements += 1
print(f"q={q},d={d},new bound = {int(bd)}, best known = {int(best)},
{bd>best}")
# tests for d>4
for d in [6,8]:
for q in prime_powers:
Q = Hdpg(q,1,2*d-1)
A,p,bd = codes.bounds.delsarte_bound_Q_matrix(Q.transpose(),2*d-1,
return_data=True,isinteger=True)
38
best = q^(2*d-1)-q*(q^(2*d-2)-1)/(q+1)
if bd<best: improvements += 1
print(f"q={q},d={d},new bound = {int(bd)}, best known = {int(best)},
{bd>best}")
print(f"Total improvements: {improvements}")
39