-
Notifications
You must be signed in to change notification settings - Fork 0
/
golayCode.js
157 lines (142 loc) · 4.21 KB
/
golayCode.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import { B, B11 } from "./constants.js";
import Matrix from "./matrix.js";
import Vector from "./vector.js";
export default class GolayCode {
/**
* 12-dim Identity matrix.
* @type {Matrix}
* @private
*/
I
/**
* Golay code generator matrix.
* @type {Matrix}
* @private
*/
G
/**
* Golay code parity check matrix.
* @type {Matrix}
* @private
*/
H
/**
* Initializes golay code and compute internal matrices.
*/
constructor() {
this.I = Matrix.buildIdentityMatrix(12);
this.G = this.I.join(B11);
this.H = this.I.verticalJoin(B);
}
/**
* Encodes a vector using golay code.
* @param {Vector} vec
* Vector to be encoded.
* @returns {Vector}
* Encoded vector.
*/
encode(vec) {
if (vec.length() != 12) {
throw "Attempted encoding when vector length = " + vec.length();
}
return new Vector(new Matrix(vec).mul(this.G).getMatrix()[0]);
}
/**
* Decodes a vector using golay code
* @param {Vector} vec
* Vector to be decoded.
* @returns {Vector}
* Decoded vector.
*/
decode(vec, u) {
if (vec.length() != 23) {
throw "Attempted decoding when vector length = " + vec.length();
}
let vecArr = vec.getVec().slice();
if (vec.weight() % 2 == 0) {
vecArr.push(1);
} else {
vecArr.push(0);
}
vec = new Vector(vecArr);
u = u || this.findErrorVector(vec);
let corrected = vec.add(u);
return new Vector(corrected.getVec().slice(0, 12));
}
/**
* Decodes a vector without error correction.
* @param {Vector} vec
* Vector to be decoded.
* @returns {Vector}
* Decoded vector.
*/
decodeNoCorrection(vec) {
return this.decode(vec, new Vector(new Array(24).fill(0)));
}
/**
* Finds error vector that can be added with transmitted vector
* where sum results in original vector if errors <= 3.
* @private
* @param {Vector} vec
* Odd weight transmitted vector with appended 0 or 1.
* @returns {Vector}
* Error vector.
*/
findErrorVector(vec) {
let s = computeSyndrome(vec, this.H);
if (s.weight() <= 3) {
return new Vector(s.getVec().concat(new Array(12).fill(0)));
}
let { sum, i } = syndromeWithBRow(s) || {};
if (sum) {
let ei = new Array(12).fill(0);
ei[i] = 1;
return new Vector(sum.getVec().concat(ei));
}
let sB = computeSyndrome(s, B);
if (sB.weight() <= 3) {
return new Vector(new Array(12).fill(0).concat(s.getVec()));
}
({ sum, i } = syndromeWithBRow(sB) || {});
if (sum) {
let ei = new Array(12).fill(0);
ei[i] = 1;
return new Vector(ei.concat(sum.getVec()));
}
throw "Error vector could not be determined";
/**
* Multiples w * M to computer syndrome.
* @param {Vector} w
* Vector to be multipled by M.
* @param {Matrix} M
* Matrix to be multiplied with w.
* @returns
* Computed syndrome value.
*/
function computeSyndrome(w, M) {
return new Vector(new Matrix(w).mul(M).getMatrix()[0]);
}
/**
* Enumerates rows of B matrix and adds each of them to s
* until sum's weight <= 2.
* @param {Vector} s
* Syndrome to be added to each B row.
* @returns {{sum: Vector, i: number}}
* Sum vector (weight <= 2) and index of B row which is the summand.
* If no such sum is found, return null.
*/
function syndromeWithBRow(s) {
for (let [i, row] of B.getMatrix().entries()) {
let sum = s.add(new Vector(row));
let weight = sum.weight();
if (weight <= 2) {
return {
sum: sum,
i: i
};
}
}
return null;
}
}
}