Commits (1)
  • Filip Ion's avatar
    -Goppa codes · 6cfcd339
    Filip Ion authored
    -Derived constructions
    -updated link to codetables.de
    6cfcd339
......@@ -172,7 +172,7 @@ def best_linear_code_in_codetables_dot_de(n, k, F, verbose=False):
param = ("?q=%s&n=%s&k=%s"%(q,n,k)).replace('L','')
url = "http://iaks-www.ira.uka.de/home/grassl/codetables/BKLC/BKLC.php"+param
url = "http://codetables.de/BKLC/BKLC.php"+param
if verbose:
print("Looking up the bounds at %s" % url)
f = urlopen(url)
......
from sage.coding.linear_code import AbstractLinearCode
from sage.coding.encoder import Encoder
from sage.coding.decoder import Decoder
from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
from sage.modules.free_module_element import vector
from sage.coding.all import codes
def _columnize(element):
v = vector(element)
return v.column()
class GoppaCode(AbstractLinearCode):
"""Implementation of Goppa codes, a generalization of BCH codes.
INPUTS:
-field -- finite filed F_q over which the code is defined
q must be a prime number
-length -- length of code
-generating_pol -- a monic polynomial with coefficients in F_q^m
-defining_set -- a set of elements of F_q^m that are not roots of g,
its cardinality must equal 'length'
EXAMPLES::
sage: from sage.coding.goppa import GoppaCode
sage: F8=GF(2**6)
sage: RR.<xx> = F8[]
sage: g = xx^9+1
sage: L = [a for a in F8.list() if g(a)!=0]
sage: len(L)
55
sage: n = 55
sage: C = GoppaCode(GF(2), n, g, L)
sage: C
[55, 16] Goppa code
"""
_registered_encoders = {}
_registered_decoders = {}
def __init__(self, field, length, generating_pol, defining_set):
super(GoppaCode, self).__init__(field, length, "GoppaEncoder", "Syndrome")
self._length = length
self._generating_pol = generating_pol
self._defining_set = defining_set
F = generating_pol.base_ring()
if (not F.is_field() or not F.is_finite()):
raise ValueError("generating_pol must be defined over a finite field")
for a in defining_set:
if generating_pol(a) == 0:
raise ValueError("Defining elements cannot be roots of generating polynomial")
def _repr_(self):
"""Representation of a Goppa code.
EXAMPLES::
sage: from sage.coding.goppa import GoppaCode
sage: F8=GF(2**3)
sage: RR.<xx> = F8[]
sage: g = xx^2+xx+1
sage: L = [a for a in F8.list() if g(a)!=0]
sage: len(L)
8
sage: n = 8
sage: C = GoppaCode(GF(2), n, g, L)
sage: C._repr_()
'[8, 2] Goppa code'
"""
return "[%s, %s] Goppa code" %(self.length(), self.dimension())
def _latex_(self):
"""Returns latex representation of self.
EXAMPLES::
sage: from sage.coding.goppa import GoppaCode
sage: F8=GF(2**3)
sage: RR.<xx> = F8[]
sage: g = xx^2+xx+1
sage: L = [a for a in F8.list() if g(a)!=0]
sage: len(L)
8
sage: n = 8
sage: C = GoppaCode(GF(2), n, g, L)
sage: C._latex_()
'\\textnormal{Goppa code of length } 8'
"""
return ("\\textnormal{Goppa code of length } %s" % self.length())
def __eq__(self, other):
"""Equality check between GoppaCode objects.
EXAMPLES::
sage: from sage.coding.goppa import GoppaCode
sage: F8=GF(2**3)
sage: RR.<xx> = F8[]
sage: g = xx^2+xx+1
sage: L = [a for a in F8.list() if g(a)!=0]
sage: len(L)
8
sage: n = 8
sage: C = GoppaCode(GF(2), n, g, L)
sage: D = GoppaCode(GF(2), n, g, L)
sage: D.__eq__(C)
True
"""
return (isinstance(other, GoppaCode)
and self.length() == other.length()
and self._generating_pol == other._generating_pol
and self._defining_set == other._defining_set)
def parity_check_matrix(self):
"""Returns a parity check matrix for 'self'.
The element in row t, column i is h[i]*(D[i]**t), where:
-h[i] is the inverse of g(D[i])
-D[i] is the ith element of the defining set
In the resulting b * n matrix we interpret each entry as an m-column vector
annd return a bm * n matrix.
EXAMPLES::
sage: from sage.coding.goppa import GoppaCode
sage: F8=GF(2**3)
sage: RR.<xx> = F8[]
sage: g = xx^2+xx+1
sage: L = [a for a in F8.list() if g(a)!=0]
sage: len(L)
8
sage: n = 8
sage: C = GoppaCode(GF(2), n, g, L)
sage: C
[8, 2] Goppa code
sage: C.parity_check_matrix()
[1 0 0 0 0 0 0 1]
[0 0 1 0 1 1 1 0]
[0 1 1 1 0 0 1 0]
[0 1 1 1 1 1 1 1]
[0 1 0 1 1 0 1 0]
[0 0 1 1 1 1 0 0]
"""
g = self._generating_pol
F = g.base_ring()
m = self.base_field().degree()
n = self._length
d = g.degree()
alpha = F.primitive_element()
D = self._defining_set
h = [(g(D[i]).inverse_of_unit()) for i in range(n)]
#assemble top row
M = _columnize(alpha)
for i in range(n):
v = _columnize(h[i])
M = M.augment(v)
M = M.delete_columns([0])
old = M
for t in range(1,d):
#assemble row
M = _columnize(alpha)
for i in range(n):
v = _columnize(h[i]*(D[i]**t))
M = M.augment(v)
M = M.delete_columns([0])
new = M
old = old.stack(new)
return old
def distance_bound(self):
"""Estimates a lower bound for the minimun distance of the code using the degree of g.
Min distance is guarenteed to be larger or equal to this bound.
EXAMPLES::
sage: from sage.coding.goppa import GoppaCode
sage: F8=GF(2**3)
sage: RR.<xx> = F8[]
sage: g = xx^2+xx+1
sage: L = [a for a in F8.list() if g(a)!=0]
sage: len(L)
8
sage: n = 8
sage: C = GoppaCode(GF(2), n, g, L)
sage: C
[8, 2] Goppa code
sage: C.distance_bound()
3
sage: C.minimum_distance()
5
"""
return 1 + (self._generating_pol).degree()
class GoppaCodeEncoder(Encoder):
def __init__(self, code):
super(GoppaCodeEncoder, self).__init__(code)
def _repr_(self):
return "Goppa encoder for the %s" % self.code()
def _latex_(self):
return "\textnormal{Goppa encoder for the } %s" % self.code()
def __eq__(self, other):
return (isinstance(other, GoppaCodeEncoder)
and self.code() == other.code())
def generator_matrix(self):
"""Returns a parity check matrix for 'self'.
The element in row t, column i is h[i]*(D[i]**t), where:
-h[i] is the inverse of g(D[i])
-D[i] is the ith element of the defining set
In the resulting b * n matrix we interpret each entry as an m-column vector
annd return a bm * n matrix.
EXAMPLES::
sage: from sage.coding.goppa import GoppaCode
sage: F8=GF(2**3)
sage: RR.<xx> = F8[]
sage: g = xx^2+xx+1
sage: L = [a for a in F8.list() if g(a)!=0]
sage: len(L)
8
sage: n = 8
sage: C = GoppaCode(GF(2), n, g, L)
sage: C
[8, 2] Goppa code
sage: C.generator_matrix()
[1 0 0 1 0 1 1 1]
[0 1 1 1 1 1 1 0]
"""
c = self.code()
pmat = c.parity_check_matrix()
aux = codes.from_parity_check_matrix(pmat)
return aux.generator_matrix()
GoppaCode._registered_encoders["GoppaEncoder"] = GoppaCodeEncoder
......@@ -310,16 +310,17 @@ def _explain_constructor(cl):
r"""
Internal function for use error messages when constructing encoders and decoders.
EXAMPLES:
sage: from sage.coding.linear_code import _explain_constructor, LinearCodeSyndromeDecoder
sage: cl = LinearCodeSyndromeDecoder
sage: _explain_constructor(cl)
"The constructor requires no arguments.\nIt takes the optional arguments ['maximum_error_weight'].\nSee the documentation of sage.coding.linear_code.LinearCodeSyndromeDecoder for more details."
sage: from sage.coding.information_set_decoder import LinearCodeInformationSetDecoder
sage: cl = LinearCodeInformationSetDecoder
sage: _explain_constructor(cl)
"The constructor requires the arguments ['number_errors'].\nIt takes the optional arguments ['algorithm'].\nIt accepts unspecified arguments as well.\nSee the documentation of sage.coding.information_set_decoder.LinearCodeInformationSetDecoder for more details."
EXAMPLES::
sage: from sage.coding.linear_code import _explain_constructor, LinearCodeSyndromeDecoder
sage: cl = LinearCodeSyndromeDecoder
sage: _explain_constructor(cl)
"The constructor requires no arguments.\nIt takes the optional arguments ['maximum_error_weight'].\nSee the documentation of sage.coding.linear_code.LinearCodeSyndromeDecoder for more details."
sage: from sage.coding.information_set_decoder import LinearCodeInformationSetDecoder
sage: cl = LinearCodeInformationSetDecoder
sage: _explain_constructor(cl)
"The constructor requires the arguments ['number_errors'].\nIt takes the optional arguments ['algorithm'].\nIt accepts unspecified arguments as well.\nSee the documentation of sage.coding.information_set_decoder.LinearCodeInformationSetDecoder for more details."
"""
import inspect
if inspect.isclass(cl):
......@@ -1317,7 +1318,7 @@ class AbstractLinearCode(Module):
@cached_method
def covering_radius(self):
r"""
Return the minimimal integer `r` such that any element in the ambient space of ``self`` has distance at most `r` to a codeword of ``self``.
Return the minimal integer `r` such that any element in the ambient space of ``self`` has distance at most `r` to a codeword of ``self``.
This method requires the optional GAP package Guava.
......@@ -1469,7 +1470,7 @@ class AbstractLinearCode(Module):
sage: C.decoder('Try')
Traceback (most recent call last):
...
ValueError: There is no Decoder named 'Try'. The known Decoders are: ['InformationSet', 'Syndrome', 'NearestNeighbor']
ValueError: There is no Decoder named 'Try'. The known Decoders are: ['InformationSet', 'NearestNeighbor', 'Syndrome']
Some decoders take extra arguments. If the user forgets to supply these,
the error message attempts to be helpful::
......@@ -1491,10 +1492,14 @@ class AbstractLinearCode(Module):
try:
return decClass(self, *args, **kwargs)
except TypeError:
raise ValueError("Constructing the {0} decoder failed, possibly due to missing or incorrect parameters.\n{1}"\
.format(decoder_name, _explain_constructor(decClass)))
raise ValueError(
"Constructing the {0} decoder failed, possibly due "
"to missing or incorrect parameters.\n{1}".format(
decoder_name, _explain_constructor(decClass)))
else:
raise ValueError("There is no Decoder named '%s'. The known Decoders are: %s" % (decoder_name, self.decoders_available()))
raise ValueError(
"There is no Decoder named '{0}'. The known Decoders are: "
"{1}".format(decoder_name, self.decoders_available()))
def decoders_available(self, classes=False):
r"""
......@@ -1512,7 +1517,7 @@ class AbstractLinearCode(Module):
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]])
sage: C = LinearCode(G)
sage: sorted(C.decoders_available())
sage: C.decoders_available()
['InformationSet', 'NearestNeighbor', 'Syndrome']
sage: dictionary = C.decoders_available(True)
......@@ -1523,7 +1528,8 @@ class AbstractLinearCode(Module):
"""
if classes:
return copy(self._registered_decoders)
return self._registered_decoders.keys()
return sorted(self._registered_decoders)
def divisor(self):
r"""
......@@ -1554,7 +1560,7 @@ class AbstractLinearCode(Module):
A linear code `C` over a field is called *projective* when its dual `Cd`
has minimum weight `\geq 3`, i.e. when no two coordinate positions of
`C` are linearly independent (cf. definition 3 from [BS2011]_ or 9.8.1 from
[BH12]).
[BH12]_).
EXAMPLES::
......@@ -1655,8 +1661,7 @@ class AbstractLinearCode(Module):
def direct_sum(self, other):
"""
Returns the code given by the direct sum of the codes ``self`` and
``other``, which must be linear codes defined over the same base ring.
Returns the code given by the direct sum of the codes ``self`` an ``other``, which must be linear codes defined over the same base ring.
EXAMPLES::
......@@ -1683,6 +1688,115 @@ class AbstractLinearCode(Module):
G = top.stack(bottom)
return LinearCode(G)
def juxtapose(self, other):
"""
Returns the code obtained by juxtaposing 'self' and 'other'.
The two codes must have equal dimension.
EXAMPLES::
sage: C1 = codes.HammingCode(GF(2), 3)
sage: C2 = C1.juxtapose(C1)
sage: C2
[14, 4] linear code over GF(2)
"""
G1 = self.generator_matrix()
G2 = other.generator_matrix()
G = G1.augment(G2)
return LinearCode(G)
def u_u_plus_v_code(self, other):
"""
Returns the code obtained through (u|u+v) construction with 'self' as u and 'other' as v.
u and v must have equal lengths. When u is a [n, k1, d1] code and v is a [n, k2, d2] code this returns a [2n, k1+k2, d] code, where d=min(2d1,d2)
EXAMPLES::
sage: C1 = codes.HammingCode(GF(2), 3)
sage: C2 = codes.HammingCode(GF(2), 3)
sage: D = C1.u_u_plus_v_code(C2)
sage: D
[14, 8] linear code over GF(2)
"""
F = self.base_ring()
G1 = self.generator_matrix()
G2 = other.generator_matrix()
k2 = len(G2.rows())
n2 = len(G2.columns())
MS = MatrixSpace(F,k2,n2)
Z = MS(0)
top = G1.augment(G1)
bot = Z.augment(G2)
G = top.stack(bot)
return LinearCode(G)
def product_code(self, other):
"""
Combines 'self' with 'other' to give the tensor product code.
If 'self' is a [n1, k1, d1] code and 'other' is a [n2, k2, d2] code, theproduct is a [n1*n2, k1*k2, d1*d2] code.
"""
G1 = self.generator_matrix()
G2 = other.generator_matrix()
G = G1.tensor_product(G2)
return LinearCode(G)
def construction_x(self, other, aux):
"""
Construction X applied to C1='self', C2='other' and Ca='aux'.
'Other' must be a subcode of 'self'. If C1 is a [n, k1, d1] linear code and C2 is a [n, k2, d2] linear code, then k1 > k2 and d1 < d2. Ca must be a [na, ka, da] linear code such that ka + k2 == k1 and da + d1 <= d2. The method will then return a [n+na, k1, da+d1] linear code.
EXAMPLES::
sage: C = codes.BCHCode(GF(2),15,7)
sage: C
[15, 5] BCH Code over GF(2) with designed distance 7
sage: D = codes.BCHCode(GF(2),15,5)
sage: D
[15, 7] BCH Code over GF(2) with designed distance 5
sage: C.is_subcode(D)
True
sage: C.minimum_distance()
7
sage: D.minimum_distance()
5
sage: aux = codes.HammingCode(GF(2),2)
sage: aux = aux.dual_code()
sage: aux.minimum_distance()
2
sage: Cx = D.construction_x(C,aux)
sage: Cx
[18, 7] linear code over GF(2)
sage: Cx.minimum_distance()
7
"""
if other.is_subcode(self) == False:
raise ValueError("%s is not a subcode of %s"%(self,other))
G2 = self.generator_matrix()
left = G1 = other.generator_matrix()
k = self.dimension()
for r in G2.rows():
if r not in left.row_space():
left = left.stack(r)
Ga = aux.generator_matrix()
na = aux.length()
ka = aux.dimension()
F = self.base_field()
MS = MatrixSpace(F,k-ka,na)
Z = MS(0)
right = Z.stack(Ga)
G = left.augment(right)
return LinearCode(G)
def __eq__(self, right):
"""
Checks if ``self`` is equal to ``right``.
......@@ -1901,10 +2015,14 @@ class AbstractLinearCode(Module):
try:
return encClass(self, *args, **kwargs)
except TypeError:
raise ValueError("Constructing the {0} encoder failed, possibly due to missing or incorrect parameters.\n{1}"\
.format(encoder_name, _explain_constructor(encClass)))
raise ValueError(
"Constructing the {0} encoder failed, possibly due "
"to missing or incorrect parameters.\n{1}".format(
encoder_name, _explain_constructor(encClass)))
else:
raise ValueError("There is no Encoder named '%s'. The known Encoders are: %s" % (encoder_name, self.encoders_available()))
raise ValueError(
"There is no Encoder named '{0}'. The known Encoders are: "
"{1}".format(encoder_name, self.encoders_available()))
def encoders_available(self, classes=False):
r"""
......@@ -1922,7 +2040,7 @@ class AbstractLinearCode(Module):
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]])
sage: C = LinearCode(G)
sage: sorted(C.encoders_available())
sage: C.encoders_available()
['GeneratorMatrix', 'Systematic']
sage: dictionary = C.encoders_available(True)
sage: sorted(dictionary.items())
......@@ -1931,7 +2049,8 @@ class AbstractLinearCode(Module):
"""
if classes:
return copy(self._registered_encoders)
return self._registered_encoders.keys()
return sorted(self._registered_encoders)
def extended_code(self):
r"""
......