Skip to content
This repository was archived by the owner on Jan 30, 2023. It is now read-only.

Commit 884d8ab

Browse files
author
David Lucas
committed
New decoder, InformationSetDecoder
1 parent 190a7be commit 884d8ab

File tree

1 file changed

+200
-10
lines changed

1 file changed

+200
-10
lines changed

src/sage/coding/linear_code.py

+200-10
Original file line numberDiff line numberDiff line change
@@ -943,13 +943,13 @@ def add_decoder(self, name, decoder):
943943
944944
sage: C.add_decoder("MyDecoder", MyDecoder)
945945
sage: C.decoders_available()
946-
['MyDecoder', 'Syndrome', 'NearestNeighbor']
946+
['MyDecoder', 'InformationSet', 'Syndrome', 'NearestNeighbor']
947947
948948
We can verify that any new code will not know MyDecoder::
949949
950950
sage: C2 = codes.HammingCode(3, GF(3))
951951
sage: C2.decoders_available()
952-
['Syndrome', 'NearestNeighbor']
952+
['InformationSet', 'Syndrome', 'NearestNeighbor']
953953
954954
TESTS:
955955
@@ -1649,7 +1649,7 @@ def decode_to_code(self, word, decoder_name=None, **kwargs):
16491649
It is possible to manually choose the decoder amongst the list of the available ones::
16501650
16511651
sage: C.decoders_available()
1652-
['Syndrome', 'NearestNeighbor']
1652+
['InformationSet', 'Syndrome', 'NearestNeighbor']
16531653
sage: C.decode_to_code(w_err, 'NearestNeighbor')
16541654
(1, 1, 0, 0, 1, 1, 0)
16551655
"""
@@ -1686,7 +1686,7 @@ def decode_to_message(self, word, decoder_name=None, **kwargs):
16861686
It is possible to manually choose the decoder amongst the list of the available ones::
16871687
16881688
sage: C.decoders_available()
1689-
['Syndrome', 'NearestNeighbor']
1689+
['InformationSet', 'Syndrome', 'NearestNeighbor']
16901690
sage: C.decode_to_message(word, 'NearestNeighbor')
16911691
(0, 1, 1, 0)
16921692
"""
@@ -1726,7 +1726,7 @@ def decoder(self, decoder_name=None, **kwargs):
17261726
an exception will be raised::
17271727
17281728
sage: C.decoders_available()
1729-
['Syndrome', 'NearestNeighbor']
1729+
['InformationSet', 'Syndrome', 'NearestNeighbor']
17301730
sage: C.decoder('Try')
17311731
Traceback (most recent call last):
17321732
...
@@ -1755,10 +1755,11 @@ def decoders_available(self, classes=False):
17551755
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]])
17561756
sage: C = LinearCode(G)
17571757
sage: C.decoders_available()
1758-
['Syndrome', 'NearestNeighbor']
1758+
['InformationSet', 'Syndrome', 'NearestNeighbor']
17591759
17601760
sage: C.decoders_available(True)
1761-
{'NearestNeighbor': <class 'sage.coding.linear_code.LinearCodeNearestNeighborDecoder'>,
1761+
{'InformationSet': <class 'sage.coding.linear_code.LinearCodeInformationSetDecoder'>,
1762+
'NearestNeighbor': <class 'sage.coding.linear_code.LinearCodeNearestNeighborDecoder'>,
17621763
'Syndrome': <class 'sage.coding.linear_code.LinearCodeSyndromeDecoder'>}
17631764
"""
17641765
if classes == True:
@@ -3008,9 +3009,10 @@ def random_element(self, *args, **kwds):
30083009
True
30093010
30103011
"""
3011-
V = self.ambient_space()
3012-
S = V.subspace(self.basis())
3013-
c = S.random_element(*args, **kwds)
3012+
E = self.encoder()
3013+
M = E.message_space()
3014+
m = M.random_element(*args, **kwds)
3015+
c = E.encode(m)
30143016
c.set_immutable()
30153017
return c
30163018

@@ -4532,6 +4534,192 @@ def decoding_radius(self):
45324534
"""
45334535
return (self.code().minimum_distance()-1) // 2
45344536

4537+
4538+
4539+
4540+
4541+
4542+
4543+
4544+
4545+
4546+
class LinearCodeInformationSetDecoder(Decoder):
4547+
r"""
4548+
Construct a decoder for Linear Codes. This decoder use the probabilistic
4549+
information set decoding algorithm. Details follow.
4550+
4551+
This decoder is based on the Lee-Brickell refinement of the information set
4552+
decoding algorithm, as described in [P10]:
4553+
4554+
Let `p` and `w` be integers, such that `0\leq p\leq w`, let
4555+
`y` be a vector over some vector space `GF(q)^{n}` and let `C` be
4556+
a `[n, k]`-linear code over `GF(q)`.
4557+
Let `G` be a generator matrix of `C`, and `G_{I}` a matrix formed by
4558+
the columns of `G` indexed by `I`.
4559+
To correct exactly `w` errors in `y`, proceed as follows:
4560+
4561+
1. Choose a information set `I` of `C`.
4562+
2. Compute `yc = y - y_{I}\times G^{-1} \times G`
4563+
3. Consider every size-`p` subset of `I` `\{a_1, \dots, a_p\}`.
4564+
For each `m= (m_1, \dots, m_p) \in GF(q)^{p}`, compute
4565+
the error vector `e = yc - \sum_{i=1}^{p} m_i\times g_{a_i}`,
4566+
4. If `e` has a Hamming weight of `w`, it's the right error vector,
4567+
thus return `y-e`.
4568+
Else, go back to 1.
4569+
4570+
4571+
4572+
REFERENCES:
4573+
4574+
- [P10] Christiane Peters, Information-set decoding for linear codes over Fq, 2010
4575+
4576+
INPUT:
4577+
4578+
- ``code`` -- A code associated to this decoder
4579+
"""
4580+
4581+
def __init__(self, code):
4582+
r"""
4583+
EXAMPLES::
4584+
4585+
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]])
4586+
sage: C = LinearCode(G)
4587+
sage: D = codes.decoders.LinearCodeInformationSetDecoder(C)
4588+
sage: D
4589+
Information set decoder for Linear code of length 7, dimension 4 over Finite Field of size 2
4590+
"""
4591+
super(LinearCodeInformationSetDecoder, self).__init__(code, code.ambient_space(), \
4592+
code._default_encoder_name)
4593+
4594+
def __eq__(self, other):
4595+
r"""
4596+
Tests equality between LinearCodeInformationSetDecoder objects.
4597+
4598+
EXAMPLES::
4599+
4600+
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]])
4601+
sage: D1 = codes.decoders.LinearCodeInformationSetDecoder(LinearCode(G))
4602+
sage: D2 = codes.decoders.LinearCodeInformationSetDecoder(LinearCode(G))
4603+
sage: D1 == D2
4604+
True
4605+
"""
4606+
return isinstance(other, LinearCodeInformationSetDecoder)\
4607+
and self.code() == other.code()
4608+
4609+
def _repr_(self):
4610+
r"""
4611+
Returns a string representation of ``self``.
4612+
4613+
EXAMPLES::
4614+
4615+
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]])
4616+
sage: C = LinearCode(G)
4617+
sage: D = codes.decoders.LinearCodeInformationSetDecoder(C)
4618+
sage: D
4619+
Information set decoder for Linear code of length 7, dimension 4 over Finite Field of size 2
4620+
"""
4621+
return "Information set decoder for %s" % self.code()
4622+
4623+
def _latex_(self):
4624+
r"""
4625+
Returns a latex representation of ``self``.
4626+
4627+
EXAMPLES::
4628+
4629+
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]])
4630+
sage: C = LinearCode(G)
4631+
sage: D = codes.decoders.LinearCodeInformationSetDecoder(C)
4632+
sage: latex(D)
4633+
\textnormal{Information set decoder for }[7, 4]\textnormal{ Linear code over }\Bold{F}_{2}
4634+
"""
4635+
return "\\textnormal{Information set decoder for }%s" % self.code()._latex_()
4636+
4637+
def decode_to_code(self, r, p, w):
4638+
r"""
4639+
Decodes ``r`` to an element in the associated code of ``self``.
4640+
4641+
One has to provide ``w``, the number of errors which ``r`` contains.
4642+
4643+
INPUT:
4644+
4645+
- ``r`` -- a received word, i.e. a vector in the ambient space of
4646+
:meth:`decoder.Decoder.code`.
4647+
4648+
- ``p`` -- the window size parameter, i.e. an integer smaller than ``w``.
4649+
4650+
- ``w`` -- the number of errors, i.e. an integer smaller than
4651+
:meth:`sage.coding.decoder.Decoder.code`'s length.
4652+
4653+
OUTPUT:
4654+
4655+
- a codeword of the associated code of ``self``
4656+
4657+
EXAMPLES::
4658+
4659+
sage: C = codes.RandomLinearCode(10, 5, GF(2))
4660+
sage: D = C.decoder('InformationSet')
4661+
sage: c = C.random_element()
4662+
sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), 3)
4663+
sage: y = Chan(c)
4664+
sage: c == D.decode_to_code(y, 2, 3)
4665+
True
4666+
"""
4667+
from sage.matrix.constructor import column_matrix
4668+
C = self.code()
4669+
n, k = C.length(), C.dimension()
4670+
if not isinstance(p, (Integer, int)) or p < 0:
4671+
raise ValueError("The window size parameter has to be either a positive Sage integer or a Python int")
4672+
if not isinstance(w, (Integer, int)) or w < 0:
4673+
raise ValueError("The provided number of errors has to be either a positive Sage integer or a Python int")
4674+
if p > w:
4675+
raise ValueError("The window size parameter has to be at most the provided number of errors")
4676+
if w > n:
4677+
raise ValueError("The provided number of errors has to be at most the code's length")
4678+
if w == 0:
4679+
return r
4680+
F = C.base_ring()
4681+
one = F.one()
4682+
G = C.generator_matrix()
4683+
columns = G.columns()
4684+
l = F.list()
4685+
#We define an iterator over the possible information sets
4686+
I = iter(Subsets(range(n), k))
4687+
while(True):
4688+
try:
4689+
information_set = list(I.next())
4690+
columns = [G.column(i) for i in information_set]
4691+
Gi = column_matrix(columns)
4692+
try:
4693+
Gi_G = Gi.inverse() * G
4694+
rc = copy(r)
4695+
#At every iteration, we will need the row corresponding
4696+
#to the index where Gi_G's i-th column has a one.
4697+
#We store this in a dictionary to save later computation.
4698+
gs = dict()
4699+
for i in information_set:
4700+
gs[i] = Gi_G.row(list(Gi_G.column(i)).index(one))
4701+
4702+
m = iter(VectorSpace(F, p))
4703+
for i in Subsets(information_set, p):
4704+
ind = 0
4705+
v = vector(F, n)
4706+
while(True):
4707+
try:
4708+
j = m.next()
4709+
v += j[ind] * gs[i[ind]]
4710+
if (rc - v).hamming_weight() == w:
4711+
return r - (rc - v)
4712+
ind = (ind + 1) % p
4713+
except StopIteration:
4714+
break
4715+
except ZeroDivisionError:
4716+
#in that case Gi was not invertible
4717+
#thus I was not an information set
4718+
pass
4719+
except StopIteration:
4720+
raise DecodingError
4721+
4722+
45354723
####################### registration ###############################
45364724

45374725
LinearCode._registered_encoders["GeneratorMatrix"] = LinearCodeGeneratorMatrixEncoder
@@ -4540,3 +4728,5 @@ def decoding_radius(self):
45404728
LinearCodeSyndromeDecoder._decoder_type = {"hard-decision", "unique", "dynamic"}
45414729
LinearCode._registered_decoders["NearestNeighbor"] = LinearCodeNearestNeighborDecoder
45424730
LinearCodeNearestNeighborDecoder._decoder_type = {"hard-decision", "unique", "always-succeed", "complete"}
4731+
LinearCode._registered_decoders["InformationSet"] = LinearCodeInformationSetDecoder
4732+
LinearCodeNearestNeighborDecoder._decoder_type = {"hard-decision", "unique", "always-succeed", "complete"}

0 commit comments

Comments
 (0)