Skip to content
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

Allow control over how the encoding matrix is built #110

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions zfec/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
from . import _version
__version__ = _version.get_versions()['version']

OPTION_POWER_SEQUENCE = 0
OPTION_SEQUENTIAL_INTEGERS = 1

from ._fec import Encoder, Decoder, Error
from . import easyfec, filefec, cmdline_zfec, cmdline_zunfec

Expand Down
18 changes: 12 additions & 6 deletions zfec/_fecmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,11 @@ Encoder_init(Encoder *self, PyObject *args, PyObject *kwdict) {
static char *kwlist[] = {
"k",
"m",
"option",
NULL
};
int ink, inm;
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "ii:Encoder.__init__", kwlist, &ink, &inm))
int ink, inm, option = FEC_OPTION_POWER_SEQUENCE;
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "ii|i:Encoder.__init__", kwlist, &ink, &inm, &option))
return -1;

if (ink < 1) {
Expand All @@ -95,11 +96,15 @@ Encoder_init(Encoder *self, PyObject *args, PyObject *kwdict) {
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);
return -1;
}
if (option != FEC_OPTION_POWER_SEQUENCE && option != FEC_OPTION_SEQUENTIAL_INTEGERS) {
PyErr_Format(py_fec_error, "Precondition violation: option third argument must be one of (%d,%d)", FEC_OPTION_POWER_SEQUENCE, FEC_OPTION_SEQUENTIAL_INTEGERS);
return -1;
}
self->kk = (unsigned short)ink;
self->mm = (unsigned short)inm;

Py_BEGIN_ALLOW_THREADS
self->fec_matrix = fec_new(self->kk, self->mm);
self->fec_matrix = fec_new2(self->kk, self->mm, option);
Py_END_ALLOW_THREADS

return 0;
Expand Down Expand Up @@ -340,11 +345,12 @@ Decoder_init(Encoder *self, PyObject *args, PyObject *kwdict) {
static char *kwlist[] = {
"k",
"m",
"option",
NULL
};

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

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

Py_BEGIN_ALLOW_THREADS
self->fec_matrix = fec_new(self->kk, self->mm);
self->fec_matrix = fec_new2(self->kk, self->mm, option);
Py_END_ALLOW_THREADS

return 0;
Expand Down
8 changes: 4 additions & 4 deletions zfec/easyfec.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ def ab(x): # debuggery
return "%s:%s" % (len(x), "--empty--",)

class Encoder(object):
def __init__(self, k, m):
self.fec = zfec.Encoder(k, m)
def __init__(self, k, m, option=0):
self.fec = zfec.Encoder(k, m, option=option)

def encode(self, data):
"""
Expand All @@ -39,8 +39,8 @@ def encode(self, data):
return self.fec.encode(l)

class Decoder(object):
def __init__(self, k, m):
self.fec = zfec.Decoder(k, m)
def __init__(self, k, m, option=0):
self.fec = zfec.Decoder(k, m, option=option)

def decode(self, blocks, sharenums, padlen):
"""
Expand Down
21 changes: 17 additions & 4 deletions zfec/fec.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,11 @@ fec_free (fec_t *p) {

fec_t *
fec_new(unsigned short k, unsigned short n) {
return fec_new2(k, n, FEC_OPTION_POWER_SEQUENCE);
}

fec_t *
fec_new2(unsigned short k, unsigned short n, fec_option_t option) {
unsigned row, col;
gf *p, *tmp_m;

Expand Down Expand Up @@ -456,16 +461,24 @@ fec_new(unsigned short k, unsigned short n) {
tmp_m[0] = 1;
for (col = 1; col < k; col++)
tmp_m[col] = 0;
for (p = tmp_m + k, row = 0; row + 1 < n; row++, p += k)
for (col = 0; col < k; col++)
p[col] = gf_exp[modnn (row * col)];
if (option == FEC_OPTION_POWER_SEQUENCE) {
for (p = tmp_m + k, row = 0; row + 1 < n; row++, p += k)
for (col = 0; col < k; col++)
p[col] = gf_exp[modnn (row * col)];
} else if (option == FEC_OPTION_SEQUENTIAL_INTEGERS) {
for (p = tmp_m + k, row = 1; row < n; row++, p += k)
for (col = 0; col < k; col++)
p[col] = gf_exp[modnn (gf_log[row] * col)];
} else {
assert(false);
}

/*
* quick code to build systematic matrix: invert the top
* k*k vandermonde matrix, multiply right the bottom n-k rows
* by the inverse, and construct the identity matrix at the top.
*/
_invert_vdm (tmp_m, k); /* much faster than _invert_mat */
_invert_mat (tmp_m, k); /* much faster than _invert_mat */
_matmul(tmp_m + k * k, tmp_m, retval->enc_matrix + k * k, n - k, k, k);
/*
* the upper matrix is I so do not bother with a slow multiply
Expand Down
25 changes: 25 additions & 0 deletions zfec/fec.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,25 @@

typedef unsigned char gf;

typedef enum {
/**
* This is the default option if you do not specify one.
* This instanciates the vandermonde matrix over a vector of
* powers of the primitive element. It ensures maximum
* separation between elements in the field, which enhances
* error correction performance.
*/
FEC_OPTION_POWER_SEQUENCE = 0,
/**
* This instanciates the vandermonde matrix over a vector of
* sequential integers. This choice is common among libraries
* that implement reed solomon erasure coding.
* Known libraries that do this:
* - klauspost/reedsolomon
*/
FEC_OPTION_SEQUENTIAL_INTEGERS = 1,
} fec_option_t;

typedef struct {
unsigned long magic;
unsigned short k, n; /* parameters of the code */
Expand Down Expand Up @@ -37,6 +56,12 @@ void fec_init(void);
* param m the total number of blocks created
*/
fec_t* fec_new(unsigned short k, unsigned short m);
/**
* param k the number of blocks required to reconstruct
* param m the total number of blocks created
* param option options that control how the encoding/decoding matrix is built.
*/
fec_t* fec_new2(unsigned short k, unsigned short m, fec_option_t option);
void fec_free(fec_t* p);

/**
Expand Down