diff --git a/erasure_code/Makefile.am b/erasure_code/Makefile.am index e354bd6..4edd4c5 100644 --- a/erasure_code/Makefile.am +++ b/erasure_code/Makefile.am @@ -172,5 +172,7 @@ perf_tests += erasure_code/gf_vect_mul_perf \ erasure_code/erasure_code_sse_perf \ erasure_code/erasure_code_update_perf +other_tests += erasure_code/gen_rs_matrix_limits + other_src += include/test.h \ include/types.h diff --git a/erasure_code/erasure_code_update_test.c b/erasure_code/erasure_code_update_test.c index a15a67b..f30a6a2 100644 --- a/erasure_code/erasure_code_update_test.c +++ b/erasure_code/erasure_code_update_test.c @@ -287,7 +287,7 @@ int main(int argc, char *argv[]) return -1; } // Pick a first test - m = 15; + m = 14; k = 10; if (m > MMAX || k > KMAX) return -1; diff --git a/erasure_code/gen_rs_matrix_limits.c b/erasure_code/gen_rs_matrix_limits.c new file mode 100644 index 0000000..8506148 --- /dev/null +++ b/erasure_code/gen_rs_matrix_limits.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include "erasure_code.h" + +#define MAX_CHECK 63 /* Size is limited by using uint64_t to represent subsets */ +#define M_MAX 0x20 +#define K_MAX 0x10 +#define ROWS M_MAX +#define COLS K_MAX + +static inline int min(int a, int b) +{ + if (a <= b) + return a; + else + return b; +} + +void gen_sub_matrix(unsigned char *out_matrix, int dim, unsigned char *in_matrix, int rows, + int cols, uint64_t row_indicator, uint64_t col_indicator) +{ + int i, j, r, s; + + for (i = 0, r = 0; i < rows; i++) { + if (!(row_indicator & ((uint64_t) 1 << i))) + continue; + + for (j = 0, s = 0; j < cols; j++) { + if (!(col_indicator & ((uint64_t) 1 << j))) + continue; + out_matrix[dim * r + s] = in_matrix[cols * i + j]; + s++; + } + r++; + } +} + +/* Gosper's Hack */ +uint64_t next_subset(uint64_t * subset, uint64_t element_count, uint64_t subsize) +{ + uint64_t tmp1 = *subset & -*subset; + uint64_t tmp2 = *subset + tmp1; + *subset = (((*subset ^ tmp2) >> 2) / tmp1) | tmp2; + if (*subset & (((uint64_t) 1 << element_count))) { + /* Overflow on last subset */ + *subset = ((uint64_t) 1 << subsize) - 1; + return 1; + } + + return 0; +} + +int are_submatrices_singular(unsigned char *vmatrix, int rows, int cols) +{ + unsigned char matrix[COLS * COLS]; + unsigned char invert_matrix[COLS * COLS]; + uint64_t row_indicator, col_indicator, subset_init, subsize; + + /* Check all square subsize x subsize submatrices of the rows x cols + * vmatrix for singularity*/ + for (subsize = 1; subsize <= min(rows, cols); subsize++) { + subset_init = (1 << subsize) - 1; + col_indicator = subset_init; + do { + row_indicator = subset_init; + do { + gen_sub_matrix(matrix, subsize, vmatrix, rows, + cols, row_indicator, col_indicator); + if (gf_invert_matrix(matrix, invert_matrix, subsize)) + return 1; + + } while (next_subset(&row_indicator, rows, subsize) == 0); + } while (next_subset(&col_indicator, cols, subsize) == 0); + } + + return 0; +} + +int main(int argc, char **argv) +{ + unsigned char vmatrix[(ROWS + COLS) * COLS]; + int rows, cols; + + if (K_MAX > MAX_CHECK) { + printf("K_MAX too large for this test\n"); + return 0; + } + if (M_MAX > MAX_CHECK) { + printf("M_MAX too large for this test\n"); + return 0; + } + if (M_MAX < K_MAX) { + printf("M_MAX must be smaller than K_MAX"); + return 0; + } + + printf("Checking gen_rs_matrix for k <= %d and m <= %d.\n", K_MAX, M_MAX); + printf("gen_rs_matrix creates erasure codes for:\n"); + + for (cols = 1; cols <= K_MAX; cols++) { + for (rows = 1; rows <= M_MAX - cols; rows++) { + gf_gen_rs_matrix(vmatrix, rows + cols, cols); + + /* Verify the Vandermonde portion of vmatrix contains no + * singular submatrix */ + if (are_submatrices_singular(&vmatrix[cols * cols], rows, cols)) + break; + + } + printf(" k = %2d, m <= %2d \n", cols, rows + cols - 1); + + } + return 0; +} diff --git a/include/erasure_code.h b/include/erasure_code.h index 53e480f..f66d838 100644 --- a/include/erasure_code.h +++ b/include/erasure_code.h @@ -884,10 +884,17 @@ unsigned char gf_inv(unsigned char a); * Vandermonde matrix example of encoding coefficients where high portion of * matrix is identity matrix I and lower portion is constructed as 2^{i*(j-k+1)} * i:{0,k-1} j:{k,m-1}. Commonly used method for choosing coefficients in - * erasure encoding but does not guarantee invertable for every sub matrix. For - * large k it is possible to find cases where the decode matrix chosen from - * sources and parity not in erasure are not invertable. Users may want to - * adjust for k > 5. + * erasure encoding but does not guarantee invertable for every sub matrix. For + * large pairs of m and k it is possible to find cases where the decode matrix + * chosen from sources and parity is not invertable. Users may want to adjust + * for certain pairs m and k. If m and k satisfy one of the following + * inequalities, no adjustment is required: + * + * k <= 3 + * k = 4, m <= 25 + * k = 5, m <= 10 + * k <= 21, m-k = 4 + * m - k <= 3. * * @param a [mxk] array to hold coefficients * @param m number of rows in matrix corresponding to srcs + parity.