前言
正如标题,本文将带领大家如何通过里德 - 所罗门纠错码实现丢失数据的修复。
百度百科:里德-所罗门码(又称里所码,Reed-solomon codes,简称RS codes)是一种前向错误更正的信道编码,对由校正过采样数据所产生的有效多项式。
正文
原始矩阵
假设原数据为 [1,3,4] ,
我们将原数据转化为 行1列3 的矩阵就得到了原始矩阵A:
//原始矩阵A
var a = [
[1],
[3],
[4]
]
编码矩阵
编码矩阵的列数等于原始矩阵的行数,行数则等于矩阵的行数加上可丢失个数;
我们这里假设可丢失个数为2,则编码矩阵B 行3列5 (3+2)。
//编码矩阵B
var b = [
[null, null, null],
[null, null, null],
[null, null, null],
[null, null, null],
[null, null, null],
]
编码矩阵B前3行3列可单独视为单位矩阵。
//编码矩阵B
var b = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
[null, null, null],
[null, null, null],
]
剩余空项只要使编码矩阵B具有任意子矩阵可逆的特性即可随意填写。
如此我们得到编码矩阵B完整结构如下:
//编码矩阵B
var b = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
[2, 1, 3],
[1, 2, 4],
]
纠错矩阵
原始矩阵A与编码矩阵B相乘得到纠错矩阵
[
[1],
[3],
[4],
[17],
[23]
]
不难看出前三位就是原数据,那么剩下的17,21就是纠错码;
得到完整数据:[1, 3, 4, 17, 23]
代码如下:
//原始矩阵A
var a = [
[1],
[3],
[4]
]
//编码矩阵B
var b = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
[2, 1, 3],
[1, 2, 4],
]
// 矩阵相乘
function multiply(a, b) {
// 相乘约束
if (a[0].length !== b.length) {
throw new Error();
}
let m = a.length;
let p = a[0].length;
let n = b[0].length;
// 初始化 m*n 全 0 二维数组
let c = new Array(m).fill(0).map(arr => new Array(n).fill(0));
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
for (let k = 0; k < p; k++) {
c[i][j] += a[i][k] * b[k][j];
}
}
}
return c;
}
console.log(multiply(b, a))
// [[1], [3], [4], [17], [23]]
还原
现在我们已经得到了完整数据,可以尝试丢失后的修复;要想还原丢失的数据,我们必须知道编码矩阵B和缺失位置;
我们假定完整数据的下标0和下标3的数据丢失,得到:
[null, 3, 4, null, 23]
转化为矩阵
var _a = [
[null],
[3],
[4],
[null],
[23]
]
删除_a与编码矩阵B缺失下标对应行:
var _a = [
// [null],
[3],
[4],
// [null],
[23]
]
var _b = [
//[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
//[2, 1, 3],
[1, 2, 4],
]
求出_b的逆矩阵与_a相乘
var _a = [
// [null],
[3],
[4],
// [null],
[23]
]
var _b = [
//[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
//[2, 1, 3],
[1, 2, 4],
]
// 转置矩阵
function transpose(matrix) {
let result = new Array(matrix.length).fill(0).map(arr => new Array(matrix[0].length).fill(0));
for (let i = 0; i < result.length; i++) {
for (let j = 0; j < result[0].length; j++) {
result[i][j] = matrix[j][i];
}
}
return result;
}
// 行列式
function det(square) {
// 方阵约束
if (square.length !== square[0].length) {
throw new Error();
}
// 方阵阶数
let n = square.length;
let result = 0;
if (n > 3) {
// n 阶
for (let column = 0; column < n; column++) {
// 去掉第 0 行第 column 列的矩阵
let matrix = new Array(n - 1).fill(0).map(arr => new Array(n - 1).fill(0));
for (let i = 0; i < n - 1; i++) {
for (let j = 0; j < n - 1; j++) {
if (j < column) {
matrix[i][j] = square[i + 1][j];
} else {
matrix[i][j] = square[i + 1][j + 1];
}
}
}
result += square[0][column] * Math.pow(-1, 0 + column) * det(matrix);
}
} else if (n === 3) {
// 3 阶
result = square[0][0] * square[1][1] * square[2][2] +
square[0][1] * square[1][2] * square[2][0] +
square[0][2] * square[1][0] * square[2][1] -
square[0][2] * square[1][1] * square[2][0] -
square[0][1] * square[1][0] * square[2][2] -
square[0][0] * square[1][2] * square[2][1];
} else if (n === 2) {
// 2 阶
result = square[0][0] * square[1][1] - square[0][1] * square[1][0];
} else if (n === 1) {
// 1 阶
result = square[0][0];
}
return result;
}
// 伴随矩阵
function adjoint(square) {
// 方阵约束
if (square[0].length !== square.length) {
throw new Error();
}
let n = square.length;
let result = new Array(n).fill(0).map(arr => new Array(n).fill(0));
for (let row = 0; row < n; row++) {
for (let column = 0; column < n; column++) {
// 去掉第 row 行第 column 列的矩阵
let matrix = [];
for (let i = 0; i < square.length; i++) {
if (i !== row) {
let arr = [];
for (let j = 0; j < square.length; j++) {
if (j !== column) {
arr.push(square[i][j]);
}
}
matrix.push(arr);
}
}
result[row][column] = Math.pow(-1, row + column) * det(matrix);
}
}
return transpose(result);
}
// 逆矩阵
function inv(square) {
if (square[0].length !== square.length) {
throw new Error();
}
let detValue = det(square);
let result = adjoint(square);
// console.log(JSON.stringify(detValue))
for (let i = 0; i < result.length; i++) {
for (let j = 0; j < result.length; j++) {
result[i][j] /= detValue;
}
}
return result;
}
// 矩阵相乘
function multiply(a, b) {
// 相乘约束
if (a[0].length !== b.length) {
throw new Error();
}
let m = a.length;
let p = a[0].length;
let n = b[0].length;
// 初始化 m*n 全 0 二维数组
let c = new Array(m).fill(0).map(arr => new Array(n).fill(0));
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
for (let k = 0; k < p; k++) {
c[i][j] += a[i][k] * b[k][j];
}
}
}
return c;
}
console.log(multiply(inv(_b), _a))
// [[1],[3],[4]]
[[1],[3],[4]]即为原始矩阵,那么也就还原出了原数据:[1,3,4]
尾声
感谢耐心阅读到这里的小伙伴们,欢迎大家在评论区留言讨论