Skip to content

Issue #40513, #40514: Allow zero code and add intersection method #40564

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
Open
33 changes: 19 additions & 14 deletions src/sage/coding/abstract_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def __init__(self, length, default_encoder_name=None,
INPUT:
- ``length`` -- the length of ``self`` (a Python int or a Sage Integer,
must be > 0)
must be >= 0)
- ``default_encoder_name`` -- (default: ``None``) the name of
the default encoder of ``self``
Expand Down Expand Up @@ -281,19 +281,24 @@ def __init__(self, length, default_encoder_name=None,
...
ValueError: length must be a Python int or a Sage Integer
If the length of the code is not a nonzero positive integer
(See :issue:`21326`), it will raise an exception::
If the length of the code is negative, it will raise an exception::
sage: C = MyCodeFamily(0)
sage: C = MyCodeFamily(-1)
Traceback (most recent call last):
...
ValueError: length must be a nonzero positive integer
ValueError: length must be a non-negative integer
Codes of length 0 are allowed::
sage: C = MyCodeFamily(0)
sage: C.length()
0
"""

if not isinstance(length, (int, Integer)):
raise ValueError("length must be a Python int or a Sage Integer")
if length <= 0:
raise ValueError("length must be a nonzero positive integer")
if length < 0:
raise ValueError("length must be a non-negative integer")

self._length = length
self._metric = metric
Expand Down Expand Up @@ -417,7 +422,7 @@ def __call__(self, m):
sage: C = LinearCode(G)
sage: word = vector((0, 1, 1, 0))
sage: C(word)
(1, 1, 0, 0, 1, 1, 0)
(0, 1, 1, 0, 0, 1, 1)
sage: c = C.random_element()
sage: C(c) == c
Expand Down Expand Up @@ -723,14 +728,14 @@ def decode_to_message(self, word, decoder_name=None, *args, **kwargs):
sage: C = LinearCode(G)
sage: word = vector(GF(2), (1, 1, 0, 0, 1, 1, 0))
sage: C.decode_to_message(word)
(0, 1, 1, 0)
(1, 1, 0, 0)
It is possible to manually choose the decoder amongst the list of the available ones::
sage: sorted(C.decoders_available())
['InformationSet', 'NearestNeighbor', 'Syndrome']
sage: C.decode_to_message(word, 'NearestNeighbor')
(0, 1, 1, 0)
(1, 1, 0, 0)
"""
return self.unencode(self.decode_to_code(word, decoder_name, *args, **kwargs), **kwargs)

Expand Down Expand Up @@ -882,17 +887,17 @@ def encode(self, word, encoder_name=None, *args, **kwargs):
sage: C = LinearCode(G)
sage: word = vector((0, 1, 1, 0))
sage: C.encode(word)
(1, 1, 0, 0, 1, 1, 0)
(0, 1, 1, 0, 0, 1, 1)
sage: C(word)
(1, 1, 0, 0, 1, 1, 0)
(0, 1, 1, 0, 0, 1, 1)
It is possible to manually choose the encoder amongst the list of the available ones::
sage: sorted(C.encoders_available())
['GeneratorMatrix', 'Systematic']
sage: word = vector((0, 1, 1, 0))
sage: C.encode(word, 'GeneratorMatrix')
(1, 1, 0, 0, 1, 1, 0)
(0, 1, 1, 0, 0, 1, 1)
"""
E = self.encoder(encoder_name, *args, **kwargs)
return E.encode(word)
Expand Down Expand Up @@ -1057,7 +1062,7 @@ def unencode(self, c, encoder_name=None, nocheck=False, **kwargs):
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: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 0))
sage: c = vector(GF(2), (0, 1, 1, 0, 0, 1, 1))
sage: C.unencode(c)
(0, 1, 1, 0)
"""
Expand Down
134 changes: 99 additions & 35 deletions src/sage/coding/linear_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,17 @@
sage: G = MS([[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: C.basis()
[(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)]
[(1, 0, 0, 0, 0, 1, 1),
(0, 1, 0, 0, 1, 0, 1),
(0, 0, 1, 0, 1, 1, 0),
(0, 0, 0, 1, 1, 1, 1)]
sage: c = C.basis()[1]
sage: c in C
True
sage: c.nonzero_positions()
[0, 3, 4]
[1, 4, 6]
sage: c.support()
[0, 3, 4]
[1, 4, 6]
sage: c.parent()
Vector space of dimension 7 over Finite Field of size 2

Expand Down Expand Up @@ -1441,7 +1441,7 @@
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: C._minimum_weight_codeword() # needs sage.libs.gap
(0, 1, 0, 1, 0, 1, 0)
(0, 0, 1, 0, 1, 1, 0)

TESTS:

Expand Down Expand Up @@ -2314,35 +2314,48 @@

sage: G = matrix(GF(2), [[0,0,0]])
sage: C = LinearCode(G)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change the Line 2313: Forbid the zero vector space.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to delete: Forbid the zero vector space (see :issue:17452 and :issue:6486)::

Traceback (most recent call last):
...
ValueError: this linear code contains no nonzero vector
sage: C
[3, 0] linear code over GF(2)
sage: C.dimension()
0
sage: C_dual = C.dual_code()
sage: C_dual
[3, 3] linear code over GF(2)
sage: C_dual.dimension() == C_dual.length()
True
"""

base_ring = generator.base_ring()
from sage.matrix.constructor import matrix

if isinstance(generator, AbstractLinearCode):
generator = generator.generator_matrix()

if hasattr(generator, 'basis'):
if generator.dimension() == 0:
G = matrix(generator.base_ring(), 0, generator.ambient_space().dimension())
else:
G = matrix(generator.basis())
else:
G = generator

base_ring = G.base_ring()
if not base_ring.is_field():
raise ValueError("'generator' must be defined on a field (not a ring)")

try:
basis = None
if hasattr(generator, "nrows"): # generator matrix case
if generator.rank() < generator.nrows():
basis = generator.row_space().basis()
else:
basis = generator.basis() # vector space etc. case
if basis is not None:
from sage.matrix.constructor import matrix
generator = matrix(base_ring, basis)
if generator.nrows() == 0:
raise ValueError("this linear code contains no nonzero vector")
except AttributeError:
# Assume input is an AbstractLinearCode, extract its generator matrix
generator = generator.generator_matrix()
if G.is_zero() or G.nrows() == 0:
super().__init__(base_ring, G.ncols(), "GeneratorMatrix", "Syndrome")
self._dimension = 0
self._generator_matrix = matrix(base_ring, 0, self.length())
self._minimum_distance = d
return

super().__init__(base_ring, generator.ncols(),
G_echelon = G.echelon_form()
generator_matrix = G_echelon.matrix_from_rows([i for i, r in enumerate(G_echelon) if not r.is_zero()])

super().__init__(base_ring, generator_matrix.ncols(),
"GeneratorMatrix", "Syndrome")
self._generator_matrix = generator
self._dimension = generator.rank()
self._generator_matrix = generator_matrix
self._dimension = self._generator_matrix.rank()
self._minimum_distance = d

def __hash__(self):
Expand Down Expand Up @@ -2382,7 +2395,58 @@
"""
return "[%s, %s]\\textnormal{ Linear code over }%s"\
% (self.length(), self.dimension(), self.base_ring()._latex_())

Check failure on line 2398 in src/sage/coding/linear_code.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (W293)

src/sage/coding/linear_code.py:2398:1: W293 Blank line contains whitespace
def intersection(self, other):
"""
Return the intersection of this linear code with another.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring should be a short summary on the first line, followed by a longer summary in subsequent paragraphs, like...

Return the intersection of this linear code with another.

The intersection of two linear codes C1 and C2 is the set of all...


The intersection of two linear codes C1 and C2 is the set of all
codewords that are in both C1 and C2. It is also a linear code.

This is computed using the identity:
C1 ∩ C2 = (C1_dual + C2_dual)_dual

INPUT:
- ``other`` -- a linear code.

OUTPUT:
- a linear code, the intersection of self and other.

EXAMPLES:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be EXAMPLES:: with two colons and a blank line after it

sage: F = GF(2)
sage: G1 = matrix(F, [[1,1,0,0], [0,0,1,1]])
sage: C1 = LinearCode(G1)
sage: G2 = matrix(F, [[1,0,1,0], [0,1,0,1]])
sage: C2 = LinearCode(G2)
sage: C_int = C1.intersection(C2)
sage: C_int
[4, 1] linear code over GF(2)
sage: c = vector(F, (1,1,1,1))
sage: c in C_int
True

# Test intersection with the zero code
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be Test intersection with the zero code:: with a blank line after it. (The :: starts a code block in RST and without it, the doctest runner won't recognize this as a test.)

sage: C_zero = LinearCode(matrix(F, [[0,0,0,0]]))
sage: C1.intersection(C_zero)
[4, 0] linear code over GF(2)
"""
if not isinstance(other, AbstractLinearCode):
raise TypeError("Intersection is only defined between linear codes.")
if self.base_field() != other.base_field():
raise TypeError("Codes must be over the same base field.")
if self.length() != other.length():
raise ValueError("Codes must have the same length.")

C1_dual = self.dual_code()
C2_dual = other.dual_code()

G1d = C1_dual.generator_matrix()
G2d = C2_dual.generator_matrix()
G_sum = G1d.stack(G2d)
sum_of_duals = LinearCode(G_sum)

return sum_of_duals.dual_code()

Check failure on line 2449 in src/sage/coding/linear_code.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (W293)

src/sage/coding/linear_code.py:2449:1: W293 Blank line contains whitespace
def generator_matrix(self, encoder_name=None, **kwargs):
r"""
Return a generator matrix of ``self``.
Expand All @@ -2401,8 +2465,8 @@
sage: G = matrix(GF(3),2,[1,-1,1,-1,1,1])
sage: code = LinearCode(G)
sage: code.generator_matrix()
[1 2 1]
[2 1 1]
[1 2 0]
[0 0 1]
"""
if encoder_name is None or encoder_name == 'GeneratorMatrix':
g = self._generator_matrix
Expand Down Expand Up @@ -2493,10 +2557,10 @@
sage: C = LinearCode(G)
sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C)
sage: E.generator_matrix()
[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]
[1 0 0 0 0 1 1]
[0 1 0 0 1 0 1]
[0 0 1 0 1 1 0]
[0 0 0 1 1 1 1]
"""
g = self.code().generator_matrix()
g.set_immutable()
Expand Down
Loading