里德 - 所罗门纠错码的原理与实现

432 阅读2分钟

前言

正如标题,本文将带领大家如何通过里德 - 所罗门纠错码实现丢失数据的修复。

百度百科:里德-所罗门码(又称里所码,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]

尾声

感谢耐心阅读到这里的小伙伴们,欢迎大家在评论区留言讨论

参考文献:www.cnblogs.com/funiyi816/p…