Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 6dd3b2a

Browse files
committedJun 18, 2024
Allow users to pick an encoding matrix that is compatible with the klauspost/reedsolomon library
1 parent 743cadf commit 6dd3b2a

File tree

5 files changed

+61
-14
lines changed

5 files changed

+61
-14
lines changed
 

‎zfec/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
from . import _version
1010
__version__ = _version.get_versions()['version']
1111

12+
OPTION_POWER_SEQUENCE = 0
13+
OPTION_SEQUENTIAL_INTEGERS = 1
14+
1215
from ._fec import Encoder, Decoder, Error
1316
from . import easyfec, filefec, cmdline_zfec, cmdline_zunfec
1417

‎zfec/_fecmodule.c

+12-6
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,11 @@ Encoder_init(Encoder *self, PyObject *args, PyObject *kwdict) {
7373
static char *kwlist[] = {
7474
"k",
7575
"m",
76+
"option",
7677
NULL
7778
};
78-
int ink, inm;
79-
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "ii:Encoder.__init__", kwlist, &ink, &inm))
79+
int ink, inm, option = FEC_OPTION_POWER_SEQUENCE;
80+
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "ii|i:Encoder.__init__", kwlist, &ink, &inm, &option))
8081
return -1;
8182

8283
if (ink < 1) {
@@ -95,11 +96,15 @@ Encoder_init(Encoder *self, PyObject *args, PyObject *kwdict) {
9596
PyErr_Format(py_fec_error, "Precondition violation: first argument is required to be less than or equal to the second argument, but they were %d and %d respectively", ink, inm);
9697
return -1;
9798
}
99+
if (option != FEC_OPTION_POWER_SEQUENCE && option != FEC_OPTION_SEQUENTIAL_INTEGERS) {
100+
PyErr_Format(py_fec_error, "Precondition violation: option third argument must be one of (%d,%d)", FEC_OPTION_POWER_SEQUENCE, FEC_OPTION_SEQUENTIAL_INTEGERS);
101+
return -1;
102+
}
98103
self->kk = (unsigned short)ink;
99104
self->mm = (unsigned short)inm;
100105

101106
Py_BEGIN_ALLOW_THREADS
102-
self->fec_matrix = fec_new(self->kk, self->mm);
107+
self->fec_matrix = fec_new2(self->kk, self->mm, option);
103108
Py_END_ALLOW_THREADS
104109

105110
return 0;
@@ -340,11 +345,12 @@ Decoder_init(Encoder *self, PyObject *args, PyObject *kwdict) {
340345
static char *kwlist[] = {
341346
"k",
342347
"m",
348+
"option",
343349
NULL
344350
};
345351

346-
int ink, inm;
347-
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "ii:Decoder.__init__", kwlist, &ink, &inm))
352+
int ink, inm, option = FEC_OPTION_POWER_SEQUENCE;
353+
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "ii|i:Decoder.__init__", kwlist, &ink, &inm, &option))
348354
return -1;
349355

350356
if (ink < 1) {
@@ -367,7 +373,7 @@ Decoder_init(Encoder *self, PyObject *args, PyObject *kwdict) {
367373
self->mm = (unsigned short)inm;
368374

369375
Py_BEGIN_ALLOW_THREADS
370-
self->fec_matrix = fec_new(self->kk, self->mm);
376+
self->fec_matrix = fec_new2(self->kk, self->mm, option);
371377
Py_END_ALLOW_THREADS
372378

373379
return 0;

‎zfec/easyfec.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ def ab(x): # debuggery
2222
return "%s:%s" % (len(x), "--empty--",)
2323

2424
class Encoder(object):
25-
def __init__(self, k, m):
26-
self.fec = zfec.Encoder(k, m)
25+
def __init__(self, k, m, option=0):
26+
self.fec = zfec.Encoder(k, m, option=option)
2727

2828
def encode(self, data):
2929
"""
@@ -39,8 +39,8 @@ def encode(self, data):
3939
return self.fec.encode(l)
4040

4141
class Decoder(object):
42-
def __init__(self, k, m):
43-
self.fec = zfec.Decoder(k, m)
42+
def __init__(self, k, m, option=0):
43+
self.fec = zfec.Decoder(k, m, option=option)
4444

4545
def decode(self, blocks, sharenums, padlen):
4646
"""

‎zfec/fec.c

+17-4
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,11 @@ fec_free (fec_t *p) {
429429

430430
fec_t *
431431
fec_new(unsigned short k, unsigned short n) {
432+
return fec_new2(k, n, FEC_OPTION_POWER_SEQUENCE);
433+
}
434+
435+
fec_t *
436+
fec_new2(unsigned short k, unsigned short n, fec_option_t option) {
432437
unsigned row, col;
433438
gf *p, *tmp_m;
434439

@@ -456,16 +461,24 @@ fec_new(unsigned short k, unsigned short n) {
456461
tmp_m[0] = 1;
457462
for (col = 1; col < k; col++)
458463
tmp_m[col] = 0;
459-
for (p = tmp_m + k, row = 0; row + 1 < n; row++, p += k)
460-
for (col = 0; col < k; col++)
461-
p[col] = gf_exp[modnn (row * col)];
464+
if (option == FEC_OPTION_POWER_SEQUENCE) {
465+
for (p = tmp_m + k, row = 0; row + 1 < n; row++, p += k)
466+
for (col = 0; col < k; col++)
467+
p[col] = gf_exp[modnn (row * col)];
468+
} else if (option == FEC_OPTION_SEQUENTIAL_INTEGERS) {
469+
for (p = tmp_m + k, row = 1; row < n; row++, p += k)
470+
for (col = 0; col < k; col++)
471+
p[col] = gf_exp[modnn (gf_log[row] * col)];
472+
} else {
473+
assert(false);
474+
}
462475

463476
/*
464477
* quick code to build systematic matrix: invert the top
465478
* k*k vandermonde matrix, multiply right the bottom n-k rows
466479
* by the inverse, and construct the identity matrix at the top.
467480
*/
468-
_invert_vdm (tmp_m, k); /* much faster than _invert_mat */
481+
_invert_mat (tmp_m, k); /* much faster than _invert_mat */
469482
_matmul(tmp_m + k * k, tmp_m, retval->enc_matrix + k * k, n - k, k, k);
470483
/*
471484
* the upper matrix is I so do not bother with a slow multiply

‎zfec/fec.h

+25
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@
88

99
typedef unsigned char gf;
1010

11+
typedef enum {
12+
/**
13+
* This is the default option if you do not specify one.
14+
* This instanciates the vandermonde matrix over a vector of
15+
* powers of the primitive element. It ensures maximum
16+
* separation between elements in the field, which enhances
17+
* error correction performance.
18+
*/
19+
FEC_OPTION_POWER_SEQUENCE = 0,
20+
/**
21+
* This instanciates the vandermonde matrix over a vector of
22+
* sequential integers. This choice is common among libraries
23+
* that implement reed solomon erasure coding.
24+
* Known libraries that do this:
25+
* - klauspost/reedsolomon
26+
*/
27+
FEC_OPTION_SEQUENTIAL_INTEGERS = 1,
28+
} fec_option_t;
29+
1130
typedef struct {
1231
unsigned long magic;
1332
unsigned short k, n; /* parameters of the code */
@@ -37,6 +56,12 @@ void fec_init(void);
3756
* param m the total number of blocks created
3857
*/
3958
fec_t* fec_new(unsigned short k, unsigned short m);
59+
/**
60+
* param k the number of blocks required to reconstruct
61+
* param m the total number of blocks created
62+
* param option options that control how the encoding/decoding matrix is built.
63+
*/
64+
fec_t* fec_new2(unsigned short k, unsigned short m, fec_option_t option);
4065
void fec_free(fec_t* p);
4166

4267
/**

0 commit comments

Comments
 (0)
Please sign in to comment.