}
@Override
public BinPolynomial decode(BinPolynomial input) throws UncorrectableErrorsException {
//Cialo z definicji kodu
GF2ToM gf = getCode().getGF();
//Syndromy
HashMap<Integer, Integer> syndromesToAlphaPowers = new HashMap<>();
boolean errors = false;
//Poszukiwanie syndromow S(1) - S(2T)
for (int i = 1; i <= 2 * getCode().getT(); i++) {
BinPolynomial currSyndrom = new BinPolynomial(0);
for (int j = 0; j < getCode().getN(); j++) {
//S(i) = R(j) * (S(i) + alfa(i*j))
if (input.getCoefficient(j)) {
currSyndrom = currSyndrom.add(gf.getAlpha((i * j) % getCode().getN()));
}
}
//Czy sa bledy
if (currSyndrom.getPolyVector().compareTo(BigInteger.ZERO) != 0) {
errors = true;
}
//Zapis potegi alfy zgodnej z syndromem na pozycji i-tej
syndromesToAlphaPowers.put(i, gf.getPower(currSyndrom));
}
//Nie ma bledow
if (!errors) {
return getData(input);
}
//Tablica na wielomian lokalizacji bledow + listy pomocnicze
int[][] errLocPoly = new int[getCode().getT() * 4 + 4][getCode().getT() * 2];
ArrayList<Integer> discrepancy = new ArrayList<>();
ArrayList<Integer> errLocPolyDeg = new ArrayList<>();
ArrayList<Integer> degStepDiff = new ArrayList<>();
//D
discrepancy.add(0, 0);
discrepancy.add(1, syndromesToAlphaPowers.get(1));
//Pierwszy wyraz wielomianu = 1 (wolny)
errLocPoly[1][0] = 1;
//Pierwszy indeks potegi = 0
errLocPoly[0][0] = 0;
for (int i = 1; i < 2 * getCode().getT(); i++) {
//Pozostale wsp wielomianu = 0
errLocPoly[1][i] = 0;
//Pozostale potegi = -1 (dla zerowych wsp wielomianu
errLocPoly[0][i] = -1;
}
//Stopien wielomianu dla 0 i 1-szego wyrazu = 0
errLocPolyDeg.add(0, 0);
errLocPolyDeg.add(1, 0);
//Odleglosc stopnia wielomianu bledu od kroku
degStepDiff.add(0, -1);
degStepDiff.add(1, 0);
//Start, dopoki nie 2t i stopien wielomianu lokalizacji bledow <= T
int currStep = 0;
do {
currStep++;
//Jezeli D dla current step == -1
if (discrepancy.get(currStep) == -1) {
//Przepisanie stopnia wielomianu do nastepnego kroku
errLocPolyDeg.add(currStep + 1, errLocPolyDeg.get(currStep));
//Przepisanie wrtosci
for (int i = 0; i <= errLocPolyDeg.get(currStep); i++) {
errLocPoly[currStep + 1][i] = errLocPoly[currStep][i];
errLocPoly[currStep][i] = gf.getPower(errLocPoly[currStep][i]);
}
} else {
//Szukamy poprzednich krokow z D > 0
int prevStep = currStep - 1;
while ((discrepancy.get(prevStep) == -1) && (prevStep > 0)) {
prevStep--;
}
//D > 0 - szukamy poprzedniego kroku z max rożnicą: stopien - krok
if (prevStep > 0) {
int j = prevStep;
while (j > 0) {
j--;
if ((discrepancy.get(j) != -1) && (degStepDiff.get(prevStep) < degStepDiff.get(j))) {
prevStep = j;
}
}
}
//Przeliczenie stopnia wielomianu lokalizacji bledow
if (errLocPolyDeg.get(currStep) > errLocPolyDeg.get(prevStep) + currStep - prevStep) {
errLocPolyDeg.add(currStep + 1, errLocPolyDeg.get(currStep));
} else {
errLocPolyDeg.add(currStep + 1, errLocPolyDeg.get(prevStep) + currStep - prevStep);
}
//Wszystkie nowe wsp. wielomianu to 0
for (int i = 0; i < 2 * getCode().getT(); i++) {
errLocPoly[currStep + 1][i] = 0;
}
//Obliczenie nowych wsp. wielomianu na podstawie wsp. wielomianu ze znalezionego poprzedniego kroku
for (int i = 0; i <= errLocPolyDeg.get(prevStep); i++) {
//Jeżeli jakaś sensowna potęga alfy z poprzedniego kroku
if (errLocPoly[prevStep][i] != -1) {
errLocPoly[currStep + 1][i + currStep - prevStep] = gf.getAlpha((discrepancy.get(currStep) + getCode().getN() - discrepancy.get(prevStep) + errLocPoly[prevStep][i]) % getCode().getN()).toUInt();
}
}
//Przepisanie wrtosci
for (int i = 0; i <= errLocPolyDeg.get(currStep); i++) {
errLocPoly[currStep + 1][i] ^= errLocPoly[currStep][i];
errLocPoly[currStep][i] = gf.getPower(errLocPoly[currStep][i]);
}
}
//Roznica: stopien - krok dla nastepnego kroku
degStepDiff.add(currStep + 1, currStep - errLocPolyDeg.get(currStep + 1));
//Krok mniejszy od 2T - mamy jeszcze syndromy - liczymy D
if (currStep < 2 * getCode().getT()) {
//Jezeli potega alfy powiazanej z syndromem jest jakaś sensowna
if (syndromesToAlphaPowers.get(currStep + 1) != -1) {
discrepancy.add(currStep + 1, gf.getAlpha(syndromesToAlphaPowers.get(currStep + 1)).toUInt());
} else {
discrepancy.add(currStep + 1, 0);
}
//D - dodawanie alf
for (int i = 1; i <= errLocPolyDeg.get(currStep + 1); i++) {
if ((syndromesToAlphaPowers.get(currStep + 1 - i) != -1) && (errLocPoly[currStep + 1][i] != 0)) {
discrepancy.add(currStep + 1, discrepancy.get(currStep + 1) ^ gf.getAlpha((syndromesToAlphaPowers.get(currStep + 1 - i) + gf.getPower(errLocPoly[currStep + 1][i])) % getCode().getN()).toUInt());
}
}
//Zapis potegi dla alfy wyniku, wartosc niepotrzebna
discrepancy.add(currStep + 1, gf.getPower(discrepancy.get(currStep + 1)));
}
} while ((currStep < 2 * getCode().getT()) && (errLocPolyDeg.get(currStep + 1) <= getCode().getT()));
currStep++;
//Warunek mozliwosci poprawy bledow
if (errLocPolyDeg.get(currStep) <= getCode().getT()) {
//Wspolczynniki wielomianu lokalizacji bledu jako potegi alf
for (int i = 0; i <= errLocPolyDeg.get(currStep); i++) {
errLocPoly[currStep][i] = gf.getPower(errLocPoly[currStep][i]);
}
//Algorytm Chien, szukanie alfa, dla ktorego wielomian lokalizacji bledow da 0 + inwersja (N - i)
ArrayList<Integer> errorLocations = new ArrayList<>();
for (int i = 1; i <= getCode().getN(); i++) {
int result = 1;
for (int j = 1; j <= errLocPolyDeg.get(currStep); j++) {
//Jezeli potega skojarzona z alfa jest sensowna
if (errLocPoly[currStep][j] != -1) {
errLocPoly[currStep][j] = (errLocPoly[currStep][j] + j) % getCode().getN();
result ^= gf.getAlpha(errLocPoly[currStep][j]).toUInt();
}
}
//alfa rozwiazaniem, wiec N-i => lokalizacja bledu
if (result == 0) {
errorLocations.add(getCode().getN() - i);