Guruswami-Sudan decoder for (Generalized) Reed-Solomon codes#
REFERENCES:
AUTHORS:
Johan S. R. Nielsen, original implementation (see [Nie] for details)
David Lucas, ported the original implementation in Sage
- class sage.coding.guruswami_sudan.gs_decoder.GRSGuruswamiSudanDecoder(code, tau=None, parameters=None, interpolation_alg=None, root_finder=None)[source]#
Bases:
Decoder
The Guruswami-Sudan list-decoding algorithm for decoding Generalized Reed-Solomon codes.
The Guruswami-Sudan algorithm is a polynomial time algorithm to decode beyond half the minimum distance of the code. It can decode up to the Johnson radius which is \(n - \sqrt(n(n-d))\), where \(n, d\) is the length, respectively minimum distance of the RS code. See [GS1999] for more details. It is a list-decoder meaning that it returns a list of all closest codewords or their corresponding message polynomials. Note that the output of the
decode_to_code
anddecode_to_message
methods are therefore lists.The algorithm has two free parameters, the list size and the multiplicity, and these determine how many errors the method will correct: generally, higher decoding radius requires larger values of these parameters. To decode all the way to the Johnson radius, one generally needs values in the order of \(O(n^2)\), while decoding just one error less requires just \(O(n)\).
This class has static methods for computing choices of parameters given the decoding radius or vice versa.
The Guruswami-Sudan consists of two computationally intensive steps: Interpolation and Root finding, either of which can be completed in multiple ways. This implementation allows choosing the sub-algorithms among currently implemented possibilities, or supplying your own.
INPUT:
code
– A code associated to this decoder.tau
– (default:None
) an integer, the number of errors one wants the Guruswami-Sudan algorithm to correct.parameters
– (default:None
) a pair of integers, where:the first integer is the multiplicity parameter, and
the second integer is the list size parameter.
interpolation_alg
– (default:None
) the interpolation algorithm that will be used. The following possibilities are currently available:"LinearAlgebra"
– uses a linear system solver."LeeOSullivan"
– uses Lee O’Sullivan method based on row reduction of a matrixNone
– one of the above will be chosen based on the size of the code and the parameters.
You can also supply your own function to perform the interpolation. See NOTE section for details on the signature of this function.
root_finder
– (default:None
) the rootfinding algorithm that will be used. The following possibilities are currently available:"Alekhnovich"
– uses Alekhnovich’s algorithm."RothRuckenstein"
– uses Roth-Ruckenstein algorithm.None
– one of the above will be chosen based on the size of the code and the parameters.
You can also supply your own function to perform the interpolation. See NOTE section for details on the signature of this function.
Note
One has to provide either
tau
orparameters
. If neither are given, an exception will be raised.If one provides a function as
root_finder
, its signature has to be:my_rootfinder(Q, maxd=default_value, precision=default_value)
. \(Q\) will be given as an element of \(F[x][y]\). The function must return the roots as a list of polynomials over a univariate polynomial ring. Seeroth_ruckenstein_root_finder()
for an example.If one provides a function as
interpolation_alg
, its signature has to be:my_inter(interpolation_points, tau, s_and_l, wy)
. Seesage.coding.guruswami_sudan.interpolation.gs_interpolation_linalg()
for an example.EXAMPLES:
sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, tau=97); D Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2)
>>> from sage.all import * >>> C = codes.GeneralizedReedSolomonCode(GF(Integer(251)).list()[:Integer(250)], Integer(70)) >>> D = codes.decoders.GRSGuruswamiSudanDecoder(C, tau=Integer(97)); D Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2)
One can specify multiplicity and list size instead of
tau
:sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, parameters=(1,2)); D Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2)
>>> from sage.all import * >>> D = codes.decoders.GRSGuruswamiSudanDecoder(C, parameters=(Integer(1),Integer(2))); D Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2)
One can pass a method as
root_finder
(works also forinterpolation_alg
):sage: from sage.coding.guruswami_sudan.gs_decoder import roth_ruckenstein_root_finder sage: rf = roth_ruckenstein_root_finder sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, parameters=(1,2), ....: root_finder=rf); D Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2)
>>> from sage.all import * >>> from sage.coding.guruswami_sudan.gs_decoder import roth_ruckenstein_root_finder >>> rf = roth_ruckenstein_root_finder >>> D = codes.decoders.GRSGuruswamiSudanDecoder(C, parameters=(Integer(1),Integer(2)), ... root_finder=rf); D Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2)
If one wants to use the native Sage algorithms for the root finding step, one can directly pass the string given in the
Input
block of this class. This works forinterpolation_alg
as well:sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, parameters=(1,2), ....: root_finder="RothRuckenstein"); D Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2)
>>> from sage.all import * >>> D = codes.decoders.GRSGuruswamiSudanDecoder(C, parameters=(Integer(1),Integer(2)), ... root_finder="RothRuckenstein"); D Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2)
Actually, we can construct the decoder from
C
directly:sage: D = C.decoder("GuruswamiSudan", tau=97); D Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2)
>>> from sage.all import * >>> D = C.decoder("GuruswamiSudan", tau=Integer(97)); D Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2)
- decode_to_code(r)[source]#
Return the list of all codeword within radius
self.decoding_radius()
of the received word \(r\).INPUT:
r
– a received word, i.e. a vector in \(F^n\) where \(F\) and \(n\) are the base field respectively length ofself.code()
.
EXAMPLES:
sage: GSD = codes.decoders.GRSGuruswamiSudanDecoder sage: C = codes.GeneralizedReedSolomonCode(GF(17).list()[:15], 6) sage: D = GSD(C, tau=5) sage: c = vector(GF(17), [3,13,12,0,0,7,5,1,8,11,1,9,4,12,14]) sage: c in C True sage: r = vector(GF(17), [3,13,12,0,0,7,5,1,8,11,15,12,14,7,10]) sage: r in C False sage: codewords = D.decode_to_code(r) sage: len(codewords) 2 sage: c in codewords True
>>> from sage.all import * >>> GSD = codes.decoders.GRSGuruswamiSudanDecoder >>> C = codes.GeneralizedReedSolomonCode(GF(Integer(17)).list()[:Integer(15)], Integer(6)) >>> D = GSD(C, tau=Integer(5)) >>> c = vector(GF(Integer(17)), [Integer(3),Integer(13),Integer(12),Integer(0),Integer(0),Integer(7),Integer(5),Integer(1),Integer(8),Integer(11),Integer(1),Integer(9),Integer(4),Integer(12),Integer(14)]) >>> c in C True >>> r = vector(GF(Integer(17)), [Integer(3),Integer(13),Integer(12),Integer(0),Integer(0),Integer(7),Integer(5),Integer(1),Integer(8),Integer(11),Integer(15),Integer(12),Integer(14),Integer(7),Integer(10)]) >>> r in C False >>> codewords = D.decode_to_code(r) >>> len(codewords) 2 >>> c in codewords True
- decode_to_message(r)[source]#
Decode
r
to the list of polynomials whose encoding byself.code()
is within Hamming distanceself.decoding_radius()
ofr
.INPUT:
r
– a received word, i.e. a vector in \(F^n\) where \(F\) and \(n\) are the base field respectively length ofself.code()
.
EXAMPLES:
sage: GSD = codes.decoders.GRSGuruswamiSudanDecoder sage: C = codes.GeneralizedReedSolomonCode(GF(17).list()[:15], 6) sage: D = GSD(C, tau=5) sage: F.<x> = GF(17)[] sage: m = 13*x^4 + 7*x^3 + 10*x^2 + 14*x + 3 sage: c = D.connected_encoder().encode(m) sage: r = vector(GF(17), [3,13,12,0,0,7,5,1,8,11,15,12,14,7,10]) sage: (c-r).hamming_weight() 5 sage: messages = D.decode_to_message(r) sage: len(messages) 2 sage: m in messages True
>>> from sage.all import * >>> GSD = codes.decoders.GRSGuruswamiSudanDecoder >>> C = codes.GeneralizedReedSolomonCode(GF(Integer(17)).list()[:Integer(15)], Integer(6)) >>> D = GSD(C, tau=Integer(5)) >>> F = GF(Integer(17))['x']; (x,) = F._first_ngens(1) >>> m = Integer(13)*x**Integer(4) + Integer(7)*x**Integer(3) + Integer(10)*x**Integer(2) + Integer(14)*x + Integer(3) >>> c = D.connected_encoder().encode(m) >>> r = vector(GF(Integer(17)), [Integer(3),Integer(13),Integer(12),Integer(0),Integer(0),Integer(7),Integer(5),Integer(1),Integer(8),Integer(11),Integer(15),Integer(12),Integer(14),Integer(7),Integer(10)]) >>> (c-r).hamming_weight() 5 >>> messages = D.decode_to_message(r) >>> len(messages) 2 >>> m in messages True
- decoding_radius()[source]#
Return the maximal number of errors that
self
is able to correct.EXAMPLES:
sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) sage: D = C.decoder("GuruswamiSudan", tau=97) sage: D.decoding_radius() 97
>>> from sage.all import * >>> C = codes.GeneralizedReedSolomonCode(GF(Integer(251)).list()[:Integer(250)], Integer(70)) >>> D = C.decoder("GuruswamiSudan", tau=Integer(97)) >>> D.decoding_radius() 97
An example where tau is not one of the inputs to the constructor:
sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) sage: D = C.decoder("GuruswamiSudan", parameters=(2,4)) sage: D.decoding_radius() 105
>>> from sage.all import * >>> C = codes.GeneralizedReedSolomonCode(GF(Integer(251)).list()[:Integer(250)], Integer(70)) >>> D = C.decoder("GuruswamiSudan", parameters=(Integer(2),Integer(4))) >>> D.decoding_radius() 105
- static gs_satisfactory(tau, s, l, C=None, n_k=None)[source]#
Return whether input parameters satisfy the governing equation of Guruswami-Sudan.
See [Nie2013] page 49, definition 3.3 and proposition 3.4 for details.
INPUT:
tau
– an integer, number of errors one expects Guruswami-Sudan algorithm to corrects
– an integer, multiplicity parameter of Guruswami-Sudan algorithml
– an integer, list size parameterC
– (default:None
) aGeneralizedReedSolomonCode
n_k
– (default:None
) a tuple of integers, respectively the length and the dimension of theGeneralizedReedSolomonCode
Note
One has to provide either
C
or(n, k)
. If none or both are given, an exception will be raised.EXAMPLES:
sage: GSD = codes.decoders.GRSGuruswamiSudanDecoder sage: tau, s, l = 97, 1, 2 sage: n, k = 250, 70 sage: GSD.gs_satisfactory(tau, s, l, n_k=(n, k)) True
>>> from sage.all import * >>> GSD = codes.decoders.GRSGuruswamiSudanDecoder >>> tau, s, l = Integer(97), Integer(1), Integer(2) >>> n, k = Integer(250), Integer(70) >>> GSD.gs_satisfactory(tau, s, l, n_k=(n, k)) True
One can also pass a GRS code:
sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) sage: GSD.gs_satisfactory(tau, s, l, C=C) True
>>> from sage.all import * >>> C = codes.GeneralizedReedSolomonCode(GF(Integer(251)).list()[:Integer(250)], Integer(70)) >>> GSD.gs_satisfactory(tau, s, l, C=C) True
Another example where
s
andl
does not satisfy the equation:sage: tau, s, l = 118, 47, 80 sage: GSD.gs_satisfactory(tau, s, l, n_k=(n, k)) False
>>> from sage.all import * >>> tau, s, l = Integer(118), Integer(47), Integer(80) >>> GSD.gs_satisfactory(tau, s, l, n_k=(n, k)) False
If one provides both
C
andn_k
an exception is returned:sage: tau, s, l = 97, 1, 2 sage: n, k = 250, 70 sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) sage: GSD.gs_satisfactory(tau, s, l, C=C, n_k=(n, k)) Traceback (most recent call last): ... ValueError: Please provide only the code or its length and dimension
>>> from sage.all import * >>> tau, s, l = Integer(97), Integer(1), Integer(2) >>> n, k = Integer(250), Integer(70) >>> C = codes.GeneralizedReedSolomonCode(GF(Integer(251)).list()[:Integer(250)], Integer(70)) >>> GSD.gs_satisfactory(tau, s, l, C=C, n_k=(n, k)) Traceback (most recent call last): ... ValueError: Please provide only the code or its length and dimension
Same if one provides none of these:
sage: GSD.gs_satisfactory(tau, s, l) Traceback (most recent call last): ... ValueError: Please provide either the code or its length and dimension
>>> from sage.all import * >>> GSD.gs_satisfactory(tau, s, l) Traceback (most recent call last): ... ValueError: Please provide either the code or its length and dimension
- static guruswami_sudan_decoding_radius(C=None, n_k=None, l=None, s=None)[source]#
Return the maximal decoding radius of the Guruswami-Sudan decoder and the parameter choices needed for this.
If
s
is set butl
is not it will return the best decoding radius using thiss
alongside with the requiredl
. Vice versa forl
. If both are set, it returns the decoding radius given this parameter choice.INPUT:
C
– (default:None
) aGeneralizedReedSolomonCode
n_k
– (default:None
) a pair of integers, respectively the length and the dimension of theGeneralizedReedSolomonCode
s
– (default:None
) an integer, the multiplicity parameter of Guruswami-Sudan algorithml
– (default:None
) an integer, the list size parameter
Note
One has to provide either
C
orn_k
. If none or both are given, an exception will be raised.OUTPUT:
(tau, (s, l))
– wheretau
is the obtained decoding radius, and(s, l)
are the multiplicity parameter and the list size parameter giving the radius
EXAMPLES:
sage: GSD = codes.decoders.GRSGuruswamiSudanDecoder sage: n, k = 250, 70 sage: GSD.guruswami_sudan_decoding_radius(n_k=(n, k)) (118, (47, 89))
>>> from sage.all import * >>> GSD = codes.decoders.GRSGuruswamiSudanDecoder >>> n, k = Integer(250), Integer(70) >>> GSD.guruswami_sudan_decoding_radius(n_k=(n, k)) (118, (47, 89))
One parameter can be restricted at a time:
sage: n, k = 250, 70 sage: GSD.guruswami_sudan_decoding_radius(n_k=(n, k), s=3) (109, (3, 5)) sage: GSD.guruswami_sudan_decoding_radius(n_k=(n, k), l=7) (111, (4, 7))
>>> from sage.all import * >>> n, k = Integer(250), Integer(70) >>> GSD.guruswami_sudan_decoding_radius(n_k=(n, k), s=Integer(3)) (109, (3, 5)) >>> GSD.guruswami_sudan_decoding_radius(n_k=(n, k), l=Integer(7)) (111, (4, 7))
The function can also just compute the decoding radius given the parameters:
sage: GSD.guruswami_sudan_decoding_radius(n_k=(n, k), s=2, l=6) (92, (2, 6))
>>> from sage.all import * >>> GSD.guruswami_sudan_decoding_radius(n_k=(n, k), s=Integer(2), l=Integer(6)) (92, (2, 6))
- interpolation_algorithm()[source]#
Return the interpolation algorithm that will be used.
Remember that its signature has to be:
my_inter(interpolation_points, tau, s_and_l, wy)
. Seesage.coding.guruswami_sudan.interpolation.gs_interpolation_linalg()
for an example.EXAMPLES:
sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) sage: D = C.decoder("GuruswamiSudan", tau=97) sage: D.interpolation_algorithm() <function gs_interpolation_lee_osullivan at 0x...>
>>> from sage.all import * >>> C = codes.GeneralizedReedSolomonCode(GF(Integer(251)).list()[:Integer(250)], Integer(70)) >>> D = C.decoder("GuruswamiSudan", tau=Integer(97)) >>> D.interpolation_algorithm() <function gs_interpolation_lee_osullivan at 0x...>
- list_size()[source]#
Return the list size parameter of
self
.EXAMPLES:
sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) sage: D = C.decoder("GuruswamiSudan", tau=97) sage: D.list_size() 2
>>> from sage.all import * >>> C = codes.GeneralizedReedSolomonCode(GF(Integer(251)).list()[:Integer(250)], Integer(70)) >>> D = C.decoder("GuruswamiSudan", tau=Integer(97)) >>> D.list_size() 2
- multiplicity()[source]#
Return the multiplicity parameter of
self
.EXAMPLES:
sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) sage: D = C.decoder("GuruswamiSudan", tau=97) sage: D.multiplicity() 1
>>> from sage.all import * >>> C = codes.GeneralizedReedSolomonCode(GF(Integer(251)).list()[:Integer(250)], Integer(70)) >>> D = C.decoder("GuruswamiSudan", tau=Integer(97)) >>> D.multiplicity() 1
- parameters()[source]#
Return the multiplicity and list size parameters of
self
.EXAMPLES:
sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) sage: D = C.decoder("GuruswamiSudan", tau=97) sage: D.parameters() (1, 2)
>>> from sage.all import * >>> C = codes.GeneralizedReedSolomonCode(GF(Integer(251)).list()[:Integer(250)], Integer(70)) >>> D = C.decoder("GuruswamiSudan", tau=Integer(97)) >>> D.parameters() (1, 2)
- static parameters_given_tau(tau, C=None, n_k=None)[source]#
Return the smallest possible multiplicity and list size given the given parameters of the code and decoding radius.
INPUT:
tau
– an integer, number of errors one wants the Guruswami-Sudan algorithm to correctC
– (default:None
) aGeneralizedReedSolomonCode
n_k
– (default:None
) a pair of integers, respectively the length and the dimension of theGeneralizedReedSolomonCode
OUTPUT:
(s, l)
– a pair of integers, where:s
is the multiplicity parameter, andl
is the list size parameter.
Note
One should to provide either
C
or(n, k)
. If neither or both are given, an exception will be raised.EXAMPLES:
sage: GSD = codes.decoders.GRSGuruswamiSudanDecoder sage: tau, n, k = 97, 250, 70 sage: GSD.parameters_given_tau(tau, n_k=(n, k)) (1, 2)
>>> from sage.all import * >>> GSD = codes.decoders.GRSGuruswamiSudanDecoder >>> tau, n, k = Integer(97), Integer(250), Integer(70) >>> GSD.parameters_given_tau(tau, n_k=(n, k)) (1, 2)
Another example with a bigger decoding radius:
sage: tau, n, k = 118, 250, 70 sage: GSD.parameters_given_tau(tau, n_k=(n, k)) (47, 89)
>>> from sage.all import * >>> tau, n, k = Integer(118), Integer(250), Integer(70) >>> GSD.parameters_given_tau(tau, n_k=(n, k)) (47, 89)
Choosing a decoding radius which is too large results in an errors:
sage: tau = 200 sage: GSD.parameters_given_tau(tau, n_k=(n, k)) Traceback (most recent call last): ... ValueError: The decoding radius must be less than the Johnson radius (which is 118.66)
>>> from sage.all import * >>> tau = Integer(200) >>> GSD.parameters_given_tau(tau, n_k=(n, k)) Traceback (most recent call last): ... ValueError: The decoding radius must be less than the Johnson radius (which is 118.66)
- rootfinding_algorithm()[source]#
Return the rootfinding algorithm that will be used.
Remember that its signature has to be:
my_rootfinder(Q, maxd=default_value, precision=default_value)
. Seeroth_ruckenstein_root_finder()
for an example.EXAMPLES:
sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) sage: D = C.decoder("GuruswamiSudan", tau=97) sage: D.rootfinding_algorithm() <function alekhnovich_root_finder at 0x...>
>>> from sage.all import * >>> C = codes.GeneralizedReedSolomonCode(GF(Integer(251)).list()[:Integer(250)], Integer(70)) >>> D = C.decoder("GuruswamiSudan", tau=Integer(97)) >>> D.rootfinding_algorithm() <function alekhnovich_root_finder at 0x...>
- sage.coding.guruswami_sudan.gs_decoder.alekhnovich_root_finder(p, maxd=None, precision=None)[source]#
Wrapper for Alekhnovich’s algorithm to compute the roots of a polynomial with coefficients in \(F[x]\).
- sage.coding.guruswami_sudan.gs_decoder.n_k_params(C, n_k)[source]#
Internal helper function for the
GRSGuruswamiSudanDecoder
class for allowing to specify either a GRS code \(C\) or the length and dimensions \(n, k\) directly, in all the static functions.If neither \(C\) or \(n,k\) were specified to those functions, an appropriate error should be raised. Otherwise, \(n, k\) of the code or the supplied tuple directly is returned.
INPUT:
C
– A GRS code orNone
n_k
– A tuple \((n,k)\) being length and dimension of a GRS code, orNone
.
OUTPUT:
n_k
– A tuple \((n,k)\) being length and dimension of a GRS code.
EXAMPLES:
sage: from sage.coding.guruswami_sudan.gs_decoder import n_k_params sage: n_k_params(None, (10, 5)) (10, 5) sage: C = codes.GeneralizedReedSolomonCode(GF(11).list()[:10], 5) sage: n_k_params(C, None) (10, 5) sage: n_k_params(None,None) Traceback (most recent call last): ... ValueError: Please provide either the code or its length and dimension sage: n_k_params(C, (12, 2)) Traceback (most recent call last): ... ValueError: Please provide only the code or its length and dimension
>>> from sage.all import * >>> from sage.coding.guruswami_sudan.gs_decoder import n_k_params >>> n_k_params(None, (Integer(10), Integer(5))) (10, 5) >>> C = codes.GeneralizedReedSolomonCode(GF(Integer(11)).list()[:Integer(10)], Integer(5)) >>> n_k_params(C, None) (10, 5) >>> n_k_params(None,None) Traceback (most recent call last): ... ValueError: Please provide either the code or its length and dimension >>> n_k_params(C, (Integer(12), Integer(2))) Traceback (most recent call last): ... ValueError: Please provide only the code or its length and dimension