Skip to content

Commit 330f236

Browse files
author
Release Manager
committed
Trac #21226: An Abstract Class for Rank Metric Codes
We propose to implement `AbstractRankMetricCode`, an abstract class for rank metric codes which will initialize the basic parameters that every rank metric code possesses. This will inherit from `AbstractCode` class. Further, we propose to add rank-metric based methods to compute distance, weight and allow for matrix to vector (and reverse) conversions between representations. Finally, we create a generic representative class `LinearRankMetricCode` as well as encoding (generator matrix, systematic) and decoding (nearest neighbour) methods. URL: https://trac.sagemath.org/21226 Reported by: arpitdm Ticket author(s): Arpit Merchant, Marketa Slukova, Johan Rosenkilde Reviewer(s): Dima Pasechnik, Johan Rosenkilde, Xavier Caruso
2 parents b9dfa0e + 899d390 commit 330f236

File tree

3 files changed

+102
-73
lines changed

3 files changed

+102
-73
lines changed

src/sage/coding/linear_code.py

-54
Original file line numberDiff line numberDiff line change
@@ -1158,60 +1158,6 @@ def construction_x(self, other, aux):
11581158
G = left.augment(right)
11591159
return LinearCode(G)
11601160

1161-
def __eq__(self, right):
1162-
"""
1163-
Checks if ``self`` is equal to ``right``.
1164-
1165-
EXAMPLES::
1166-
1167-
sage: C1 = codes.HammingCode(GF(2), 3)
1168-
sage: C2 = codes.HammingCode(GF(2), 3)
1169-
sage: C1 == C2
1170-
True
1171-
1172-
TESTS:
1173-
1174-
We check that :trac:`16644` is fixed::
1175-
1176-
sage: C = codes.HammingCode(GF(2), 3)
1177-
sage: C == ZZ
1178-
False
1179-
"""
1180-
if not (isinstance(right, LinearCode)\
1181-
and self.length() == right.length()\
1182-
and self.dimension() == right.dimension()\
1183-
and self.base_ring() == right.base_ring()):
1184-
return False
1185-
Ks = self.parity_check_matrix().right_kernel()
1186-
rbas = right.gens()
1187-
if not all(c in Ks for c in rbas):
1188-
return False
1189-
Kr = right.parity_check_matrix().right_kernel()
1190-
sbas = self.gens()
1191-
if not all(c in Kr for c in sbas):
1192-
return False
1193-
return True
1194-
1195-
def __ne__(self, other):
1196-
r"""
1197-
Tests inequality of ``self`` and ``other``.
1198-
1199-
This is a generic implementation, which returns the inverse of ``__eq__`` for self.
1200-
1201-
EXAMPLES::
1202-
1203-
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]])
1204-
sage: C1 = LinearCode(G)
1205-
sage: C2 = LinearCode(G)
1206-
sage: C1 != C2
1207-
False
1208-
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,1,1]])
1209-
sage: C2 = LinearCode(G)
1210-
sage: C1 != C2
1211-
True
1212-
"""
1213-
return not self == other
1214-
12151161
def extended_code(self):
12161162
r"""
12171163
Returns `self` as an extended code.

src/sage/coding/linear_code_no_metric.py

+73-1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,22 @@ def __init__(self, base_field, length, default_encoder_name, default_decoder_nam
157157
- ``default_decoder_name`` -- the name of the default decoder of ``self``
158158
159159
- ``metric`` -- (default: ``Hamming``) the metric of ``self``
160+
161+
EXAMPLES:
162+
163+
sage: from sage.coding.linear_code_no_metric import AbstractLinearCodeNoMetric
164+
sage: from sage.coding.linear_code import LinearCodeSyndromeDecoder
165+
sage: class MyLinearCode(AbstractLinearCodeNoMetric):
166+
....: def __init__(self, field, length, dimension, generator_matrix):
167+
....: self._registered_decoders['Syndrome'] = LinearCodeSyndromeDecoder
168+
....: AbstractLinearCodeNoMetric.__init__(self, field, length, "Systematic", "Syndrome")
169+
....: self._dimension = dimension
170+
....: self._generator_matrix = generator_matrix
171+
....: def generator_matrix(self):
172+
....: return self._generator_matrix
173+
....: def _repr_(self):
174+
....: return "[%d, %d] dummy code over GF(%s)" % (self.length(), self.dimension(), self.base_field().cardinality())
175+
sage: C = MyLinearCode(GF(2), 1, 1, matrix(GF(2), [1]))
160176
"""
161177

162178
self._registered_encoders['Systematic'] = LinearCodeSystematicEncoder
@@ -227,7 +243,63 @@ def generator_matrix(self, encoder_name=None, **kwargs):
227243
return E.generator_matrix()
228244

229245
def __eq__(self, other):
230-
return self.generator_matrix() == other.generator_matrix()
246+
r"""
247+
Tests equality between two linear codes.
248+
249+
EXAMPLES::
250+
251+
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]])
252+
sage: C1 = LinearCode(G)
253+
sage: C1 == 5
254+
False
255+
sage: C2 = LinearCode(G)
256+
sage: C1 == C2
257+
True
258+
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,1,1]])
259+
sage: C2 = LinearCode(G)
260+
sage: C1 == C2
261+
False
262+
sage: G = Matrix(GF(3), [[1,2,1,0,0,0,0]])
263+
sage: C3 = LinearCode(G)
264+
sage: C1 == C3
265+
False
266+
"""
267+
# Fail without computing the generator matrix if possible:
268+
if not (isinstance(other, AbstractLinearCodeNoMetric)\
269+
and self.length() == other.length()\
270+
and self.dimension() == other.dimension()\
271+
and self.base_ring() == other.base_ring()):
272+
return False
273+
# Check that basis elements of `other` are all in `self.`
274+
# Since we're over a field and since the dimensions match, the codes
275+
# must be equal.
276+
# This implementation may avoid linear algebra altogether, if `self`
277+
# implements an efficient way to obtain a parity check matrix, and in
278+
# the worst case does only one system solving.
279+
for c in other.gens():
280+
if not (c in self):
281+
return False
282+
return True
283+
284+
def __ne__(self, other):
285+
r"""
286+
Tests inequality of ``self`` and ``other``.
287+
288+
This is a generic implementation, which returns the inverse of ``__eq__`` for self.
289+
290+
EXAMPLES::
291+
292+
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]])
293+
sage: C1 = LinearCode(G)
294+
sage: C2 = LinearCode(G)
295+
sage: C1 != C2
296+
False
297+
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,1,1]])
298+
sage: C2 = LinearCode(G)
299+
sage: C1 != C2
300+
True
301+
"""
302+
return not self == other
231303

232304
def dimension(self):
233305
r"""

src/sage/coding/linear_rank_metric.py

+29-18
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ def to_matrix_representation(v, sub_field=None, basis=None):
153153
154154
- ``basis`` -- (default: ``None``) a basis of `F_{q^m}` as a vector space over
155155
``sub_field``. If not specified, given that `q = p^s`, let
156-
`1,\beta,\ldots,\beta^{sm}` be the power basis that SageMath uses to
157-
represent `F_{q^m}`. The default basis is then `1,\beta,\ldots,beta^{m-1}`.
156+
`1,β,\ldots,β^{sm}` be the power basis that SageMath uses to
157+
represent `F_{q^m}`. The default basis is then `1,β,\ldots,β^{m-1}`.
158158
159159
EXAMPLES::
160160
@@ -204,8 +204,8 @@ def from_matrix_representation(w, base_field=None, basis=None):
204204
205205
- ``basis`` -- (default: ``None``) a basis of `F_{q^m}` as a vector space over
206206
``F_q``. If not specified, given that `q = p^s`, let
207-
`1,\beta,\ldots,\beta^{sm}` be the power basis that SageMath uses to
208-
represent `F_{q^m}`. The default basis is then `1,\beta,\ldots,beta^{m-1}`.
207+
`1,β,\ldots,β^{sm}` be the power basis that SageMath uses to
208+
represent `F_{q^m}`. The default basis is then `1,β,\ldots,β^{m-1}`.
209209
210210
EXAMPLES::
211211
@@ -247,8 +247,8 @@ def rank_weight(c, sub_field=None, basis=None):
247247
248248
- ``basis`` -- (default: ``None``) a basis of `F_{q^m}` as a vector space over
249249
``sub_field``. If not specified, given that `q = p^s`, let
250-
`1,\beta,\ldots,\beta^{sm}` be the power basis that SageMath uses to
251-
represent `F_{q^m}`. The default basis is then `1,\beta,\ldots,beta^{m-1}`.
250+
`1,β,\ldots,β^{sm}` be the power basis that SageMath uses to
251+
represent `F_{q^m}`. The default basis is then `1,β,\ldots,β^{m-1}`.
252252
253253
EXAMPLES::
254254
@@ -284,8 +284,8 @@ def rank_distance(a, b, sub_field=None, basis=None):
284284
285285
- ``basis`` -- (default: ``None``) a basis of `F_{q^m}` as a vector space over
286286
``sub_field``. If not specified, given that `q = p^s`, let
287-
`1,\beta,\ldots,\beta^{sm}` be the power basis that SageMath uses to
288-
represent `F_{q^m}`. The default basis is then `1,\beta,\ldots,beta^{m-1}`.
287+
`1,β,\ldots,β^{sm}` be the power basis that SageMath uses to
288+
represent `F_{q^m}`. The default basis is then `1,β,\ldots,β^{m-1}`.
289289
290290
EXAMPLES::
291291
@@ -386,8 +386,8 @@ def __init__(self, base_field, sub_field, length, default_encoder_name,
386386
387387
- ``basis`` -- (default: ``None``) a basis of `F_{q^m}` as a vector space over
388388
``sub_field``. If not specified, given that `q = p^s`, let
389-
`1,\beta,\ldots,\beta^{sm}` be the power basis that SageMath uses to
390-
represent `F_{q^m}`. The default basis is then `1,\beta,\ldots,beta^{m-1}`.
389+
`1,β,\ldots,β^{sm}` be the power basis that SageMath uses to
390+
represent `F_{q^m}`. The default basis is then `1,β,\ldots,β^{m-1}`.
391391
392392
EXAMPLES:
393393
@@ -558,10 +558,11 @@ def minimum_distance(self):
558558
559559
EXAMPLES::
560560
561-
sage: G = Matrix(GF(64), [[1,1,0], [0,0,1]])
562-
sage: C = codes.LinearRankMetricCode(G, GF(4))
561+
sage: F.<a> = GF(8)
562+
sage: G = Matrix(F, [[1,a,a^2,0]])
563+
sage: C = codes.LinearRankMetricCode(G, GF(2))
563564
sage: C.minimum_distance()
564-
1
565+
3
565566
"""
566567
d = Infinity
567568
for c in self:
@@ -681,8 +682,8 @@ def __init__(self, generator, sub_field=None, basis=None):
681682
682683
- ``basis`` -- (default: ``None``) a basis of `F_{q^m}` as a vector space over
683684
``sub_field``. If not specified, given that `q = p^s`, let
684-
`1,\beta,\ldots,\beta^{sm}` be the power basis that SageMath uses to
685-
represent `F_{q^m}`. The default basis is then `1,\beta,\ldots,beta^{m-1}`.
685+
`1,β,\ldots,β^{sm}` be the power basis that SageMath uses to
686+
represent `F_{q^m}`. The default basis is then `1,β,\ldots,β^{m-1}`.
686687
687688
EXAMPLES::
688689
@@ -860,6 +861,15 @@ def decode_to_code(self, r):
860861
OUTPUT:
861862
862863
- a vector of ``self``'s message space
864+
865+
EXAMPLES::
866+
867+
sage: F.<a> = GF(4)
868+
sage: G = Matrix(F, [[1,1,0]])
869+
sage: C = codes.LinearRankMetricCode(G, GF(2))
870+
sage: D = codes.decoders.LinearRankMetricCodeNearestNeighborDecoder(C)
871+
sage: D.decode_to_code(vector(F, [a, a, 1]))
872+
(a, a, 0)
863873
"""
864874
C = self.code()
865875
c_min = C.zero()
@@ -877,11 +887,12 @@ def decoding_radius(self):
877887
878888
EXAMPLES::
879889
880-
sage: G = Matrix(GF(64), [[1,1,0], [0,0,1]])
881-
sage: C = codes.LinearRankMetricCode(G, GF(4))
890+
sage: F.<a> = GF(8)
891+
sage: G = Matrix(F, [[1,a,a^2,0]])
892+
sage: C = codes.LinearRankMetricCode(G, GF(2))
882893
sage: D = codes.decoders.LinearRankMetricCodeNearestNeighborDecoder(C)
883894
sage: D.decoding_radius()
884-
0
895+
1
885896
"""
886897
return (self.code().minimum_distance()-1) // 2
887898

0 commit comments

Comments
 (0)