Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/coding/delsarte_bounds.py
8815 views
1
r"""
2
Delsarte, a.k.a. Linear Programming (LP), upper bounds.
3
4
This module provides LP upper bounds for the parameters of codes.
5
Exact LP solver, PPL, is used by defaut, ensuring that no rounding/overflow
6
problems occur.
7
8
AUTHORS:
9
10
- Dmitrii V. (Dima) Pasechnik (2012-10): initial implementation.
11
"""
12
#*****************************************************************************
13
# Copyright (C) 2012 Dima Pasechnik <[email protected]>
14
#
15
# Distributed under the terms of the GNU General Public License (GPL)
16
#
17
# http://www.gnu.org/licenses/
18
#*****************************************************************************
19
def Krawtchouk(n,q,l,i):
20
"""
21
Compute ``K^{n,q}_l(i)``, the Krawtchouk polynomial:
22
see :wikipedia:`Kravchuk_polynomials`.
23
It is given by
24
25
.. math::
26
27
K^{n,q}_l(i)=\sum_{j=0}^l (-1)^j(q-1)^{(l-j)}{i \choose j}{n-i \choose l-j}
28
29
EXAMPLES::
30
31
sage: Krawtchouk(24,2,5,4)
32
2224
33
sage: Krawtchouk(12300,4,5,6)
34
567785569973042442072
35
36
"""
37
from sage.rings.arith import binomial
38
# Use the expression in equation (55) of MacWilliams & Sloane, pg 151
39
# We write jth term = some_factor * (j-1)th term
40
kraw = jth_term = (q-1)**l * binomial(n, l) # j=0
41
for j in range(1,l+1):
42
jth_term *= -q*(l-j+1)*(i-j+1)/((q-1)*j*(n-j+1))
43
kraw += jth_term
44
return kraw
45
46
def _delsarte_LP_building(n, d, d_star, q, isinteger, solver, maxc = 0):
47
"""
48
LP builder - common for the two functions; not exported.
49
50
EXAMPLES::
51
52
sage: from sage.coding.delsarte_bounds import _delsarte_LP_building
53
sage: _,p=_delsarte_LP_building(7, 3, 0, 2, False, "PPL")
54
sage: p.show()
55
Maximization:
56
x_0 + x_1 + x_2 + x_3 + x_4 + x_5 + x_6 + x_7
57
Constraints:
58
constraint_0: 1 <= x_0 <= 1
59
constraint_1: 0 <= x_1 <= 0
60
constraint_2: 0 <= x_2 <= 0
61
constraint_3: -7 x_0 - 5 x_1 - 3 x_2 - x_3 + x_4 + 3 x_5 + 5 x_6 + 7 x_7 <= 0
62
constraint_4: -7 x_0 - 5 x_1 - 3 x_2 - x_3 + x_4 + 3 x_5 + 5 x_6 + 7 x_7 <= 0
63
constraint_5: -21 x_0 - 9 x_1 - x_2 + 3 x_3 + 3 x_4 - x_5 - 9 x_6 - 21 x_7 <= 0
64
constraint_6: -21 x_0 - 9 x_1 - x_2 + 3 x_3 + 3 x_4 - x_5 - 9 x_6 - 21 x_7 <= 0
65
constraint_7: -35 x_0 - 5 x_1 + 5 x_2 + 3 x_3 - 3 x_4 - 5 x_5 + 5 x_6 + 35 x_7 <= 0
66
constraint_8: -35 x_0 - 5 x_1 + 5 x_2 + 3 x_3 - 3 x_4 - 5 x_5 + 5 x_6 + 35 x_7 <= 0
67
constraint_9: -35 x_0 + 5 x_1 + 5 x_2 - 3 x_3 - 3 x_4 + 5 x_5 + 5 x_6 - 35 x_7 <= 0
68
constraint_10: -35 x_0 + 5 x_1 + 5 x_2 - 3 x_3 - 3 x_4 + 5 x_5 + 5 x_6 - 35 x_7 <= 0
69
constraint_11: -21 x_0 + 9 x_1 - x_2 - 3 x_3 + 3 x_4 + x_5 - 9 x_6 + 21 x_7 <= 0
70
constraint_12: -21 x_0 + 9 x_1 - x_2 - 3 x_3 + 3 x_4 + x_5 - 9 x_6 + 21 x_7 <= 0
71
constraint_13: -7 x_0 + 5 x_1 - 3 x_2 + x_3 + x_4 - 3 x_5 + 5 x_6 - 7 x_7 <= 0
72
constraint_14: -7 x_0 + 5 x_1 - 3 x_2 + x_3 + x_4 - 3 x_5 + 5 x_6 - 7 x_7 <= 0
73
constraint_15: - x_0 + x_1 - x_2 + x_3 - x_4 + x_5 - x_6 + x_7 <= 0
74
constraint_16: - x_0 + x_1 - x_2 + x_3 - x_4 + x_5 - x_6 + x_7 <= 0
75
Variables:
76
x_0 is a continuous variable (min=0, max=+oo)
77
x_1 is a continuous variable (min=0, max=+oo)
78
x_2 is a continuous variable (min=0, max=+oo)
79
x_3 is a continuous variable (min=0, max=+oo)
80
x_4 is a continuous variable (min=0, max=+oo)
81
x_5 is a continuous variable (min=0, max=+oo)
82
x_6 is a continuous variable (min=0, max=+oo)
83
x_7 is a continuous variable (min=0, max=+oo)
84
85
"""
86
from sage.numerical.mip import MixedIntegerLinearProgram
87
88
p = MixedIntegerLinearProgram(maximization=True, solver=solver)
89
A = p.new_variable(integer=isinteger) # A>=0 is assumed
90
p.set_objective(sum([A[r] for r in xrange(n+1)]))
91
p.add_constraint(A[0]==1)
92
for i in xrange(1,d):
93
p.add_constraint(A[i]==0)
94
for j in xrange(1,n+1):
95
rhs = sum([Krawtchouk(n,q,j,r)*A[r] for r in xrange(n+1)])
96
p.add_constraint(0*A[0] <= rhs)
97
if j >= d_star:
98
p.add_constraint(0*A[0] <= rhs)
99
else: # rhs is proportional to j-th weight of the dual code
100
p.add_constraint(0*A[0] == rhs)
101
102
if maxc > 0:
103
p.add_constraint(sum([A[r] for r in xrange(n+1)]), max=maxc)
104
return A, p
105
106
def delsarte_bound_hamming_space(n, d, q, return_data=False, solver="PPL"):
107
"""
108
Find the classical Delsarte bound [1]_ on codes in Hamming space
109
``H_q^n`` of minimal distance ``d``
110
111
112
INPUT:
113
114
- ``n`` -- the code length
115
116
- ``d`` -- the (lower bound on) minimal distance of the code
117
118
- ``q`` -- the size of the alphabet
119
120
- ``return_data`` -- if ``True``, return a triple ``(W,LP,bound)``, where ``W`` is
121
a weights vector, and ``LP`` the Delsarte bound LP; both of them are Sage LP
122
data. ``W`` need not be a weight distribution of a code.
123
124
- ``solver`` -- the LP/ILP solver to be used. Defaults to ``PPL``. It is arbitrary
125
precision, thus there will be no rounding errors. With other solvers
126
(see :class:`MixedIntegerLinearProgram` for the list), you are on your own!
127
128
129
EXAMPLES:
130
131
The bound on the size of the `F_2`-codes of length 11 and minimal distance 6::
132
133
sage: delsarte_bound_hamming_space(11, 6, 2)
134
12
135
sage: a, p, val = delsarte_bound_hamming_space(11, 6, 2, return_data=True)
136
sage: [j for i,j in p.get_values(a).iteritems()]
137
[1, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0]
138
139
The bound on the size of the `F_2`-codes of length 24 and minimal distance
140
8, i.e. parameters of the extened binary Golay code::
141
142
sage: a,p,x=delsarte_bound_hamming_space(24,8,2,return_data=True)
143
sage: x
144
4096
145
sage: [j for i,j in p.get_values(a).iteritems()]
146
[1, 0, 0, 0, 0, 0, 0, 0, 759, 0, 0, 0, 2576, 0, 0, 0, 759, 0, 0, 0, 0, 0, 0, 0, 1]
147
148
The bound on the size of `F_4`-codes of length 11 and minimal distance 3::
149
150
sage: delsarte_bound_hamming_space(11,3,4)
151
327680/3
152
153
Such an input is invalid::
154
155
sage: delsarte_bound_hamming_space(11,3,-4)
156
Solver exception: 'PPL : There is no feasible solution' ()
157
False
158
159
REFERENCES:
160
161
.. [1] P. Delsarte, An algebraic approach to the association schemes of coding theory,
162
Philips Res. Rep., Suppl., vol. 10, 1973.
163
164
165
166
"""
167
from sage.numerical.mip import MIPSolverException
168
A, p = _delsarte_LP_building(n, d, 0, q, False, solver)
169
try:
170
bd=p.solve()
171
except MIPSolverException, exc:
172
print "Solver exception: ", exc, exc.args
173
if return_data:
174
return A,p,False
175
return False
176
177
if return_data:
178
return A,p,bd
179
else:
180
return bd
181
182
def delsarte_bound_additive_hamming_space(n, d, q, d_star=1, q_base=0,
183
return_data=False, solver="PPL", isinteger=False):
184
"""
185
Find the Delsarte LP bound on ``F_{q_base}``-dimension of additive codes in
186
Hamming space ``H_q^n`` of minimal distance ``d`` with minimal distance of the dual
187
code at least ``d_star``. If ``q_base`` is set to
188
non-zero, then ``q`` is a power of ``q_base``, and the code is, formally, linear over
189
``F_{q_base}``. Otherwise it is assumed that ``q_base==q``.
190
191
192
INPUT:
193
194
- ``n`` -- the code length
195
196
- ``d`` -- the (lower bound on) minimal distance of the code
197
198
- ``q`` -- the size of the alphabet
199
200
- ``d_star`` -- the (lower bound on) minimal distance of the dual code;
201
only makes sense for additive codes.
202
203
- ``q_base`` -- if ``0``, the code is assumed to be nonlinear. Otherwise,
204
``q=q_base^m`` and the code is linear over ``F_{q_base}``.
205
206
- ``return_data`` -- if ``True``, return a triple ``(W,LP,bound)``, where ``W`` is
207
a weights vector, and ``LP`` the Delsarte bound LP; both of them are Sage LP
208
data. ``W`` need not be a weight distribution of a code, or,
209
if ``isinteger==False``, even have integer entries.
210
211
- ``solver`` -- the LP/ILP solver to be used. Defaults to ``PPL``. It is arbitrary
212
precision, thus there will be no rounding errors. With other solvers
213
(see :class:`MixedIntegerLinearProgram` for the list), you are on your own!
214
215
- ``isinteger`` -- if ``True``, uses an integer programming solver (ILP), rather
216
that an LP solver. Can be very slow if set to ``True``.
217
218
EXAMPLES:
219
220
The bound on dimension of linear `F_2`-codes of length 11 and minimal distance 6::
221
222
sage: delsarte_bound_additive_hamming_space(11, 6, 2)
223
3
224
sage: a,p,val=delsarte_bound_additive_hamming_space(11, 6, 2,\
225
return_data=True)
226
sage: [j for i,j in p.get_values(a).iteritems()]
227
[1, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0]
228
229
The bound on the dimension of linear `F_4`-codes of length 11 and minimal distance 3::
230
231
sage: delsarte_bound_additive_hamming_space(11,3,4)
232
8
233
234
The bound on the `F_2`-dimension of additive `F_4`-codes of length 11 and minimal
235
distance 3::
236
237
sage: delsarte_bound_additive_hamming_space(11,3,4,q_base=2)
238
16
239
240
Such a d_star is not possible::
241
242
sage: delsarte_bound_additive_hamming_space(11,3,4,d_star=9)
243
Solver exception: 'PPL : There is no feasible solution' ()
244
False
245
246
"""
247
from sage.numerical.mip import MIPSolverException
248
if q_base == 0:
249
q_base = q
250
251
kk = 0
252
while q_base**kk < q:
253
kk += 1
254
255
if q_base**kk != q:
256
print "Wrong q_base=", q_base, " for q=", q, kk
257
return False
258
259
# this implementation assumes that our LP solver to be unable to do a hot
260
# restart with an adjusted constraint
261
262
m = kk*n # this is to emulate repeat/until block
263
bd = q**n+1
264
265
while q_base**m < bd: # need to solve the LP repeatedly, as this is a new constraint!
266
# we might become infeasible. More precisely, after rounding down
267
# to the closest value of q_base^m, the LP, with the constraint that
268
# the objective function is at most q_base^m,
269
A, p = _delsarte_LP_building(n, d, d_star, q, isinteger, solver, q_base**m)
270
try:
271
bd=p.solve()
272
except MIPSolverException, exc:
273
print "Solver exception: ", exc, exc.args
274
if return_data:
275
return A,p,False
276
return False
277
# rounding the bound down to the nearest power of q_base, for q=q_base^m
278
# bd_r = roundres(log(bd, base=q_base))
279
m = -1
280
while q_base**(m+1) < bd:
281
m += 1
282
if q_base**(m+1) == bd:
283
m += 1
284
285
if return_data:
286
return A, p, m
287
else:
288
return m
289
290