From ef6291effa5721fdce06f45e74bf736626510bc8 Mon Sep 17 00:00:00 2001 From: MichalMroz <125133223+MichalMroz21@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:18:59 +0200 Subject: [PATCH] Boost refactoring Added boost, refactored code --- include/ReedSolomonCode.hpp | 9 +- source/HammingCode.cpp | 193 +++-- source/ReedSolomonCode.cpp | 774 +++++++++--------- .../FormComponents/VisualizeCheckbox.qml | 4 +- 4 files changed, 504 insertions(+), 476 deletions(-) diff --git a/include/ReedSolomonCode.hpp b/include/ReedSolomonCode.hpp index 3fdfb01..568a42f 100644 --- a/include/ReedSolomonCode.hpp +++ b/include/ReedSolomonCode.hpp @@ -155,13 +155,14 @@ public slots: void endErrorCorrection(); private: - static const int k = 5, nsym = 2, fieldPower = 3, total = k + nsym; - + static constexpr int k = 5, nsym = 2, fieldPower = 3, total = k + nsym; QString data{}, receivedCode{}, dataEncoded{}; - int dataArr[k], receivedCodeArr[total], dataEncodedArr[total]; - int animationDelayMs{}; + + int dataArr[k], receivedCodeArr[total], dataEncodedArr[total], animationDelayMs{}; + volatile bool infiniteWait = false, buttonPressed = false, shouldQuit = false, finished = true; + GaloisField gf; void waitForQml(); diff --git a/source/HammingCode.cpp b/source/HammingCode.cpp index c4630a5..37ed100 100644 --- a/source/HammingCode.cpp +++ b/source/HammingCode.cpp @@ -4,6 +4,14 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + HammingCode::HammingCode(QObject *parent) : QObject{parent}{} void HammingCode::setInitialData(QBitArray data, bool extend, int animationDelay, bool infiniteWait){ @@ -16,15 +24,12 @@ void HammingCode::setInitialData(QBitArray data, bool extend, int animationDelay this->receivedCode.clear(); } -void HammingCode::setInitialData(QString data, bool extend, int animationDelay, bool infiniteWait) -{ - int n = data.size(); - - QBitArray bits(n); +void HammingCode::setInitialData(QString data, bool extend, int animationDelay, bool infiniteWait){ + QBitArray bits(data.size()); - for(int i = 0; i < n; i++){ - bits[i] = (data[i].toLatin1() - '0'); - } + boost::transform(data.toStdString(), const_cast(bits.bits()), + [](QChar c) { return c.toLatin1() - '0'; } + ); setInitialData(bits, extend, animationDelay, infiniteWait); } @@ -38,9 +43,9 @@ void HammingCode::sendCode(QString send){ QBitArray code(send.size()); - for(int i = 0; i < send.size(); i++){ - code[i] = send[i].toLatin1() - '0'; - } + boost::transform(send.toStdString(), const_cast(code.bits()), + [](QChar c) { return c.toLatin1() - '0'; } + ); sendCode(code); } @@ -51,6 +56,8 @@ int HammingCode::correctErrorExtended(bool forQML) QString belowText{}, initialText{"C = %1"}, addText{"C += %1"}, belowTextExt{}; + auto getBit = [&](int i) { return receivedCode.testBit(i) ? 1 : 0; }; + if(forQML){ emit setBelowText(initialText.arg(C)); this->waitForQml(); @@ -126,26 +133,26 @@ int HammingCode::correctErrorExtended(bool forQML) this->waitForQml(); } - for(int i = 0; i < n; i++){ - - if(forQML){ + if (forQML) { + boost::for_each(boost::irange(0, n), [&](int i) { emit turnBitOn(0, i, "light green"); - belowText.append(QString(i == 0 ? "%1" : " ^ %1").arg(receivedCode[i])); + belowText.append(QString(i == 0 ? "%1" : " ^ %1").arg(getBit(i))); emit setBelowText(belowText); belowTextExt.append(QString(i == 0 ? "%1" : " ^ %1").arg(this->getSymbol(i))); emit setBelowTextExtended(belowTextExt); this->waitForQml(); emit turnBitOff(0, i); - } - - P ^= receivedCode[i]; + }); } + P = boost::accumulate(boost::irange(0, n), P, [&](int acc, int i) { return acc ^ getBit(i); }); + emit setBelowTextExtended(QString("")); emit setBelowText(QString("C = %1, P = %2").arg(C).arg(P)); - int ret; + int ret{}; + if(C == 0){ //theory from youtube if(P == 1){ qInfo() << "Error is in extended parity bit"; @@ -182,8 +189,7 @@ int HammingCode::correctErrorExtended(bool forQML) return ret; } -int HammingCode::correctErrorStandard(bool forQML) -{ +int HammingCode::correctErrorStandard(bool forQML){ int n = this->m + this->p, C{}, bit{}; QString belowText{}, initialText{"C = %1"}, addText{"C += %1"}, belowTextExt{}; @@ -252,8 +258,11 @@ int HammingCode::correctErrorStandard(bool forQML) } this->setError(C); - int ret; + + int ret{}; + emit setBelowText("C = " + QString::number(C)); + if(C == 0){ //theory from youtube qInfo() << "There is no error!"; emit setBelowTextExtendedTranslation(11, {""}); @@ -272,8 +281,7 @@ int HammingCode::correctErrorStandard(bool forQML) } //Correct the 1 bit error in received code -int HammingCode::correctError(bool forQML) -{ +int HammingCode::correctError(bool forQML){ if(forQML){ this->finished = false; if(this->encodingExtended){ @@ -307,14 +315,12 @@ int HammingCode::calculateP(){ } return newP; - } bool HammingCode::isPowerTwo(int n){ return (n > 0) && ((n & (n - 1)) == 0); //O(1) trick } - void HammingCode::encodeData(bool forQML){ if(forQML){ @@ -512,13 +518,11 @@ QString HammingCode::getDataStr() return ret; } -int HammingCode::getAnimationDelayMs() const -{ +int HammingCode::getAnimationDelayMs() const{ return animationDelayMs; } -void HammingCode::setAnimationDelayMs(int delay) -{ +void HammingCode::setAnimationDelayMs(int delay){ this->animationDelayMs = delay; } @@ -536,11 +540,9 @@ QBitArray HammingCode::getData(){ QString HammingCode::getReceivedCode() { QString ret{}; - - for(int i = 0; i < this->receivedCode.size(); i++){ - ret.append(QChar(this->receivedCode[i] + '0')); - } - + boost::transform(std::string(receivedCode.bits()), std::back_inserter(ret), [](char bit) { + return QChar( bit ? '1' : '0' ); + }); return ret; } @@ -548,8 +550,7 @@ bool HammingCode::getEncodingExtended() const{ return encodingExtended; } -void HammingCode::setInfiniteWait(bool value) -{ +void HammingCode::setInfiniteWait(bool value){ this->infiniteWait = value; } @@ -562,8 +563,7 @@ bool HammingCode::isFinished() { return this->finished; } -void HammingCode::waitForQml() -{ +void HammingCode::waitForQml(){ if (this->infiniteWait) { while (!this->buttonPressed && this->infiniteWait && !this->shouldQuit); this->buttonPressed = false; @@ -572,8 +572,7 @@ void HammingCode::waitForQml() QThread::currentThread()->msleep(this->animationDelayMs); } -void HammingCode::pressButton() -{ +void HammingCode::pressButton(){ this->buttonPressed = true; } @@ -584,29 +583,37 @@ QString HammingCode::getGenerationMatrixStr() { QString ret{}; - int numOfCols = this->m + this->p; - int numOfRows = this->m; + int numOfCols = this->m + this->p, + numOfRows = this->m, + position = 3; // position in the encoded data of non-parity bit, 1 and 2 are parity + + for(const auto i : boost::irange(numOfRows)) { + QStringList parityRow; - int position = 3; // position in the encoded data of non-parity bit, 1 and 2 are parity - for(int i = 0; i < numOfRows; i++) { - QString parityRow{}; while (isPowerTwo(position)) position++; // has to be non-parity - int n = i; - int parityBitCounter = 0; + + int n = i, parityBitCounter = 0; + for (int j = 0; j < numOfCols; j++) { - bool bitUsedInCurrentPosition = false; - bool isParity = isPowerTwo(j + 1); + + bool bitUsedInCurrentPosition = false, + isParity = isPowerTwo(j + 1); + if(!isParity) { bitUsedInCurrentPosition = ((n--) == 0); // bit used at n-th non-parity position ret.append(QChar(bitUsedInCurrentPosition ? '1' : '0')); - } else { + } + else { bitUsedInCurrentPosition = (1 << parityBitCounter) & position; parityBitCounter++; parityRow.append(QChar(bitUsedInCurrentPosition ? '1' : '0')); } } - ret.append(parityRow); // non-parity columns first - makes the matrix canonical + + ret.append(parityRow.join("")); + if (i != numOfRows - 1) ret.append(QChar('\n')); + position++; } @@ -622,51 +629,50 @@ QString HammingCode::getGenerationMatrixStr() QString HammingCode::getErrorMatrixStr() { QString ret{}; - int numOfCols = this->m + this->p; - int numOfRows = this->p; + int numOfCols = this->m + this->p, + numOfRows = this->p; - for(int i = 0; i < numOfRows; i++) { + for (const auto i : boost::irange(numOfRows)) { QString row{}; - int zeroCount = (1 << i) - 1; - int colCounter = 0; - for (int j = 0; j < zeroCount; j++) { - row.append(QChar('0')); - colCounter++; - } + int zeroCount = (1 << i) - 1, + colCounter = 0; + + std::fill_n(std::back_inserter(row), zeroCount, '0'); + colCounter += zeroCount; + bool insertZero = false; int howManyInARow = (1 << i); + while (colCounter < numOfCols) { - for (int j = 0; j < howManyInARow && colCounter < numOfCols; j++) { - row.append(QChar(insertZero ? '0' : '1')); - colCounter++; - } + int remainingCols = std::min(howManyInARow, numOfCols - colCounter); + char value = insertZero ? '0' : '1'; + std::fill_n(std::back_inserter(row), remainingCols, value); + colCounter += remainingCols; insertZero = !insertZero; } + if (i != 0) row.append(QChar('\n')); ret.prepend(row); } + return ret; } - QString HammingCode::getEncodedStr() { - QString ret{}; - QString error = getError(); - QString received = getReceivedCode(); + QString ret{}, error = getError(), received = getReceivedCode(); - // Perform XOR operation character by character - for (int i = 0; i < error.length(); ++i) { - // Convert characters to integers and perform XOR - int errorBit = error.at(i).digitValue(); - int receivedBit = received.at(i).digitValue(); - int xorResult = errorBit ^ receivedBit; + auto combinedStrings = boost::combine(error.toStdString(), received.toStdString()); - ret.append(QString::number(xorResult)); - } + boost::transform(combinedStrings, std::back_inserter(ret), [](const auto& pair) { + int errorBit = boost::get<0>(pair) - '0', + receivedBit = boost::get<1>(pair) - '0', + xorResult = errorBit ^ receivedBit; - return ret; + return static_cast(xorResult + '0'); + }); + return ret; } QString HammingCode::getError() { @@ -677,15 +683,15 @@ QString HammingCode::getSyndrome() { return this->syndrome; } -void HammingCode::setError(int C) -{ - this->error = {}; +void HammingCode::setError(int C){ int syndromeLength = qCeil(qLn(this->m + this->p) / qLn(2)); + + this->error = {}; this->syndrome = QString::number(C, 2).rightJustified(syndromeLength, '0'); // converts to binary, left padded with 0s - for (int i = 0; i < this->m + this->p; i++) { + + for (int i : boost::irange(0, this->m + this->p)) { this->error.append(QChar(i == C - 1 ? '1' : '0')); } - } QString HammingCode::getSymbol(int index) { @@ -694,9 +700,10 @@ QString HammingCode::getSymbol(int index) { void HammingCode::setSymbols() { this->symbols = {}; - int parityIndex = 0; - int dataIndex = 0; - for (int i = 0; i < this->m + this->p; i++) { + + int parityIndex = 0, dataIndex = 0; + + for (int i : boost::irange(0, this->m + this->p)) { QString symbol; if (isPowerTwo(i + 1)) symbol = QString("p%1").arg(parityIndex++); else symbol = QString("d%1").arg(dataIndex++); @@ -705,12 +712,16 @@ void HammingCode::setSymbols() { } QString HammingCode::getDecodedStr() { - QString ret {}; - QString encoded = getEncodedStr(); - for (int i = this->encodingExtended ? 1 : 0; i < this->m + this->p; i++) { - if (isPowerTwo(this->encodingExtended ? i : i + 1)) continue; + QString ret {}, encoded = getEncodedStr(); + + auto nonParityFilter = [this](int i) { + return !isPowerTwo(this->encodingExtended ? i : i + 1); + }; + + for (int i : boost::irange(this->encodingExtended ? 1 : 0, this->m + this->p) + | boost::adaptors::filtered(nonParityFilter)) { ret.append(encoded.at(i)); } return ret; - } + diff --git a/source/ReedSolomonCode.cpp b/source/ReedSolomonCode.cpp index bf2966e..aa1ba02 100644 --- a/source/ReedSolomonCode.cpp +++ b/source/ReedSolomonCode.cpp @@ -4,98 +4,114 @@ #include #include -ReedSolomonCode::ReedSolomonCode(QObject *parent) : QObject{parent}, gf(fieldPower) { -} - -Poly ReedSolomonCode::getRemainder(QString data) -{ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ReedSolomonCode::ReedSolomonCode(QObject *parent) : QObject{parent}, gf(fieldPower) {} + +Poly ReedSolomonCode::getRemainder(QString data){ this->data = data; - for (int i = 0; i < data.length(); i++) - { - this->dataArr[i] = data.at(i).toLatin1() - '0'; - } - Poly msg(this->k, this->dataArr); - Poly generator, remainder; + + boost::transform(data.toStdString(), dataArr, + [](QChar c) { return c.toLatin1() - '0'; } + ); + + Poly msg(this->k, this->dataArr), + generator, remainder; + this->createGenerator(&generator, true); + Poly_Pad(&msg, 0, nsym); Poly_Div(nullptr, nullptr, &remainder, &msg, &generator, &this->gf); + return remainder; } -void ReedSolomonCode::setInitialData(QString data, int animationDelay, bool infiniteWait) -{ - assert(data.length() == this->k); +void ReedSolomonCode::setInitialData(QString data, int animationDelay, bool infiniteWait){ + BOOST_ASSERT(data.length() == this->k); + this->animationDelayMs = animationDelay; this->infiniteWait = infiniteWait; this->data = data; - for (int i = 0; i < data.length(); i++) - { + + for (int i : boost::irange(data.length())) { this->dataArr[i] = data.at(i).toLatin1() - '0'; } } -void ReedSolomonCode::encodeData(bool forQML) -{ - if(forQML) - { +void ReedSolomonCode::encodeData(bool forQML){ + if(forQML){ this->finished = false; static_cast(QtConcurrent::run([=, this](){ encodeDataAsync(forQML); })); } - else - { + else{ encodeDataAsync(forQML); } } -void ReedSolomonCode::encodeDataAsync(bool forQML) -{ - Poly msg(this->k, this->dataArr); - Poly generator, remainder; +void ReedSolomonCode::encodeDataAsync(bool forQML){ + Poly msg(this->k, this->dataArr), + generator{}, remainder{}; + this->createGenerator(&generator, forQML); - if(forQML) - { + + if(forQML){ emit pushEmptyArray(this->total); - for (int i = 0; i < this->k; i++) - { + + for (int i : boost::irange(this->k)) { emit setBit(0, i, this->data.at(i)); } - for (int i = k; i < total; i++) - { - emit setBit(0, i, QChar('a' + i - k)); + + for (int i : boost::irange(this->k, this->total)) { + emit setBit(0, i, QChar('a' + i - this->k)); } + emit setBelowTextTranslation(9, {""}); emit setBelowTextExtended(""); this->waitForQml(); } + Poly_Pad(&msg, 0, nsym); Poly_Div(nullptr, nullptr, &remainder, &msg, &generator, &this->gf); - if (forQML) { - Poly msgRev; + + if (forQML){ + + Poly msgRev{}, genRev{}; + Poly_Reverse(&msgRev, &msg); - Poly genRev; Poly_Reverse(&genRev, &generator); + emit setBelowTextExtended(QString("(%1) / (%2) = ? + (%3)") .arg(msgRev.toString()) .arg(genRev.toString()) .arg(remainder.toString())); + emit setBelowTextTranslation(10, {""}); + this->waitForQml(); - for (int i = k; i < total; i++) - { - emit setBit(0, i, QChar('0' + remainder.coef[i - k])); + + for (int i : boost::irange(this->k, this->total)) { + emit setBit(0, i, QChar('0' + remainder.coef[i - this->k])); this->waitForQml(); } } - memcpy(this->dataEncodedArr, this->dataArr, sizeof(int) * k); - memcpy(this->dataEncodedArr + k, remainder.coef, sizeof(int) * remainder.n); + std::memcpy(this->dataEncodedArr, this->dataArr, sizeof(int) * k); + std::memcpy(this->dataEncodedArr + k, remainder.coef, sizeof(int) * remainder.n); - this->dataEncoded = {}; - for (int i = 0; i < this->total; i++) - { + dataEncoded.clear(); + + for (int i : boost::irange(0, this->total)) { this->dataEncoded.append(QChar(this->dataEncodedArr[i] + '0')); } @@ -110,23 +126,24 @@ void ReedSolomonCode::correctErrorQml() { })); } -int ReedSolomonCode::getRet(int n, int* coef) -{ - Poly synd; - Poly msg(n, coef); +int ReedSolomonCode::getRet(int n, int* coef){ + Poly synd{}, msg(n, coef); + this->calcSyndromes(&synd, &msg, false); int ret; - Poly fsynd, errLoc; + Poly fsynd{}, errLoc{}; + this->forneySyndromes(&fsynd, &synd, k + nsym); + bool canLocate1 = this->findErrorLocator(&errLoc, &fsynd, false); - std::vector pos; + std::vector pos{}; + bool canLocate2 = this->findErrors(&pos, &errLoc, k + nsym, false); - if (pos.size()) - { + if (pos.size()){ ret = pos[0]; } @@ -135,114 +152,117 @@ int ReedSolomonCode::getRet(int n, int* coef) return ret; } -int ReedSolomonCode::correctError(bool forQML) -{ - Poly synd; - Poly msg(k + nsym, this->receivedCodeArr); +int ReedSolomonCode::correctError(bool forQML){ + Poly synd, msg(k + nsym, this->receivedCodeArr); this->calcSyndromes(&synd, &msg, forQML); - int ret; - if (this->checkSyndromes(&synd)) - { + + int ret{}; + + if (this->checkSyndromes(&synd)){ if (forQML) { emit setBelowTextTranslation(11, {""}); } ret = -1; } - else - { - if (forQML) - { + else{ + if (forQML){ emit setBelowTextTranslation(12, {""}); this->waitForQml(); } + qInfo() << "Występują błędy, wyszukiwanie pozycji"; - Poly fsynd, errLoc; + + Poly fsynd{}, errLoc{}; + this->forneySyndromes(&fsynd, &synd, k + nsym); + bool canLocate = this->findErrorLocator(&errLoc, &fsynd, forQML); - if (!canLocate) - { + + if (!canLocate){ qInfo() << "Zbyt dużo błędów do znalezienia!"; - if (forQML) - { + if (forQML){ emit setBelowTextTranslation(13, {""}); emit endErrorCorrection(); } return -1; } - if (forQML) - { - Poly revErrLoc; + if (forQML){ + Poly revErrLoc{}; Poly_Reverse(&revErrLoc, &errLoc); emit setBelowTextTranslation(14, {""}); emit setBelowTextExtended(revErrLoc.toString()); this->waitForQml(); } - std::vector pos; + + std::vector pos{}; canLocate = this->findErrors(&pos, &errLoc, k + nsym, forQML); - if (!canLocate || !(pos.size())) - { + + if (!canLocate || !(pos.size())){ qInfo() << "Nie udało się znaleźć błędów!"; - if (forQML) - { + + if (forQML){ emit setBelowTextTranslation(15, {""}); emit endErrorCorrection(); } + return -1; } - if (pos.size()) - { + if (pos.size()){ + qInfo() << "Dodatkowe błędy znalezione na pozycjach: "; - for_each(pos.begin(), pos.end(), [](unsigned int e) {qInfo() << (int)e << ", "; }); + + std::for_each(pos.begin(), pos.end(), [](unsigned int e) {qInfo() << (int)e << ", "; }); + ret = pos[0]; - if (forQML) - { + + if (forQML){ emit setBelowTextTranslation(16, {QString::number(ret + 1)}); emit setBelowTextExtended(""); this->waitForQml(); } } + bool success = this->correctErrata(&msg, &synd, &pos, forQML); - if (!success) - { + + if (!success){ qInfo() << "Nie udało się zdekodować!"; - if (forQML) - { + + if (forQML){ emit setBelowTextTranslation(17, {""}); emit endErrorCorrection(); } return -1; } QString poprawione = {}; - for (int i = 0; i < this->total; i++) - { + + for (int i = 0; i < this->total; i++){ poprawione.append(QChar(msg.coef[i] + '0')); } - if (forQML) - { + + if (forQML){ emit setBelowTextTranslation(18, {QString::number(ret + 1)}); emit setBelowTextExtendedTranslation(19, {poprawione}); } + qInfo() << "Poprawiono błędy"; } + if(forQML) emit endErrorCorrection(); this->finished = true; return ret; } -int ReedSolomonCode::getAnimationDelayMs() const -{ +int ReedSolomonCode::getAnimationDelayMs() const{ return animationDelayMs; } -void ReedSolomonCode::setAnimationDelayMs(int delay) -{ +void ReedSolomonCode::setAnimationDelayMs(int delay){ this->animationDelayMs = delay; } -void ReedSolomonCode::setInfiniteWait(bool value) -{ +void ReedSolomonCode::setInfiniteWait(bool value){ this->infiniteWait = value; } @@ -255,46 +275,42 @@ bool ReedSolomonCode::isFinished() { return this->finished; } -void ReedSolomonCode::waitForQml() -{ - if (this->infiniteWait) - { +void ReedSolomonCode::waitForQml(){ + if (this->infiniteWait){ while (!this->buttonPressed && this->infiniteWait && !this->shouldQuit); this->buttonPressed = false; } - else - QThread::currentThread()->msleep(this->animationDelayMs); + else QThread::currentThread()->msleep(this->animationDelayMs); } -void ReedSolomonCode::pressButton() -{ +void ReedSolomonCode::pressButton(){ this->buttonPressed = true; } -void ReedSolomonCode::sendCode(QString sent) -{ +void ReedSolomonCode::sendCode(QString sent){ this->receivedCode = sent; - for (int i = 0; i < sent.length(); i++) - { - this->receivedCodeArr[i] = sent.at(i).toLatin1() - '0'; - } + boost::transform(sent, receivedCodeArr, + [](QChar c) { return c.toLatin1() - '0'; } + ); } -QString ReedSolomonCode::getDataEncoded() const -{ +QString ReedSolomonCode::getDataEncoded() const{ return this->dataEncoded; } -QString toString(int* arr, int size) -{ +QString toString(int* arr, int size){ QString result{}; + bool plus = false; - for (int i = size - 1; i >= 0; i--) - { + + for (int i = size - 1; i >= 0; i--){ if (arr[i] == 0) continue; + QString x = QString("x^%1 ").arg(i); + if (i == 1) x = "x "; if (i == 0) x = ""; + result.append(QString("%1%2%3") .arg(plus ? "+ " : "") .arg(QChar('0' + arr[i])) @@ -302,34 +318,34 @@ QString toString(int* arr, int size) ); plus = true; } + return result; } - -std::vector toVector(QString s) -{ +std::vector toVector(QString s){ std::vector result(s.length()); - for (QChar c : s) - { + + foreach (QChar c, s){ result.push_back(c.toLatin1() - '0'); } + return result; } -void ReedSolomonCode::createGenerator(Poly* out, bool forQML) -{ +void ReedSolomonCode::createGenerator(Poly* out, bool forQML){ out->setCopy(1, nullptr); out->coef[0] = 1; + Poly factor(2, nullptr); factor.coef[0] = 1; - for (int i = 0; i < this->nsym; i++) - { + + for (int i : boost::irange(0, this->nsym)) { factor.coef[1] = this->gf.powTable[i]; Poly_Mult(out, out, &factor, &this->gf); } - if (forQML) - { - Poly genRev; + + if (forQML){ + Poly genRev{}; Poly_Reverse(&genRev, out); //emit setBelowText("Wielomian generujący"); emit setBelowTextTranslation(20, {""}); @@ -338,60 +354,59 @@ void ReedSolomonCode::createGenerator(Poly* out, bool forQML) } } -void ReedSolomonCode::calcSyndromes(Poly* out, Poly* msg, bool forQML) -{ - int* temp = (int*)malloc(sizeof(int) * (nsym + 1)); - for (int i = 0; i < nsym; i++) - { +void ReedSolomonCode::calcSyndromes(Poly* out, Poly* msg, bool forQML){ + std::vector temp(nsym + 1); + + for (int i = 0; i < nsym; i++){ QString text = QString("(%1)(%2)").arg(msg->toString()).arg(this->gf.powTable[i]); - if (forQML) - { - emit setBelowTextCalcSyndromes((i+1), i); + + if (forQML) { + emit setBelowTextCalcSyndromes((i + 1), i); emit setBelowTextExtended(text); this->waitForQml(); } + temp[nsym - i - 1] = Poly_Eval(msg, this->gf.powTable[i], &this->gf); - if (forQML) - { - text.append(QString(" = %1").arg(temp[nsym - i -1])); - qInfo() << "text: " << text; - emit setBelowTextExtended(text); + + if (forQML){ + QString evalText = (boost::format("%1 = %2") % text.toStdString() % temp[nsym - i - 1]).str().c_str(); + emit setBelowTextExtended(evalText); this->waitForQml(); } } - temp[nsym] = 0; //pad - out->setRef(nsym + 1, temp); - if (forQML) - { + + temp[nsym] = 0; + + out->setRef(nsym + 1, temp.data()); + + if (forQML) { emit setBelowText(""); emit setBelowTextExtended(""); } } -bool ReedSolomonCode::checkSyndromes(Poly* synd) -{ - for (int i = 0; i < synd->n; i++) - { - if (synd->coef[i]) - { +bool ReedSolomonCode::checkSyndromes(Poly* synd){ + for (int i : boost::irange(synd->n)){ + if (synd->coef[i]){ return false; } } return true; } -void ReedSolomonCode::findErrataLocator(Poly* out, std::vector* errPos, bool forQML) -{ +void ReedSolomonCode::findErrataLocator(Poly* out, std::vector* errPos, bool forQML){ out->setCopy(1, nullptr); out->coef[0] = 1; + Poly factor(2, nullptr); factor.coef[1] = 1; - for (unsigned int i : *errPos) - { + + for (unsigned int i : *errPos){ + factor.coef[0] = this->gf.powTable[i]; Poly_Mult(out, out, &factor, &this->gf); - if (forQML) - { + + if (forQML){ emit setBelowText("errata_locator = 1x + 2 ^ coef_pos"); emit setBelowTextExtended(QString("1x + 2^%1 = %2").arg(i).arg(out->toString())); this->waitForQml(); @@ -399,218 +414,234 @@ void ReedSolomonCode::findErrataLocator(Poly* out, std::vector* er } } -void ReedSolomonCode::findErrorEvaluator(Poly* out, Poly* synd, Poly* errLoc, int nsym, bool forQML) -{ +void ReedSolomonCode::findErrorEvaluator(Poly* out, Poly* synd, Poly* errLoc, int nsym, bool forQML){ Poly_Mult(out, synd, errLoc, &this->gf); //synd lul - { - emit setBelowText("syndrom * errata_locator = error_evaluator * x^2 + bx + c"); - emit setBelowTextExtended(QString("(%1) * (%2) = %3").arg(synd->toString()).arg(errLoc->toString()).arg(out->toString())); - this->waitForQml(); - } + + emit setBelowText("syndrom * errata_locator = error_evaluator * x^2 + bx + c"); + emit setBelowTextExtended(QString("(%1) * (%2) = %3").arg(synd->toString()).arg(errLoc->toString()).arg(out->toString())); + + this->waitForQml(); + Poly_Trim(out, out->n - nsym, 0); - if (forQML) - { + + if (forQML){ emit setBelowText("error_evaluator"); emit setBelowTextExtended(QString("%1").arg(out->toString())); this->waitForQml(); } } -bool ReedSolomonCode::correctErrata(Poly* msg, Poly* synd, std::vector* errPos, bool forQML) -{ - if (forQML) - { +bool ReedSolomonCode::correctErrata(Poly* msg, Poly* synd, std::vector* errPos, bool forQML){ + if (forQML){ emit setBelowTextTranslation(23, {""}); emit setBelowTextExtended(""); this->waitForQml(); } + std::vector coefPos(0); - for (unsigned int i : *errPos) - { + + for (unsigned int i : *errPos){ + coefPos.push_back(msg->n - 1 - i); - if (forQML) - { + + if (forQML){ emit setTopTextTranslation(23, {""}); emit setBelowTextTranslation(24, {""}); emit setBelowTextExtended(QString("coef_pos = %1").arg(msg->n - 1 - i)); this->waitForQml(); } } - Poly errLoc, errEval; + + Poly errLoc{}, errEval{}; + this->findErrataLocator(&errLoc, &coefPos, forQML); - if (forQML) - { + + if (forQML){ qInfo() << "Errata locator: " << errLoc.toString(); } + this->findErrorEvaluator(&errEval, synd, &errLoc, errLoc.n, forQML); - if (forQML) - { + + if (forQML){ qInfo() << "Evaluator: " << errEval.toString(); } + //Poly_Reverse(errEval, errEval); //reverse it for later use std::vector x(coefPos.size()); - for (int i = 0; i < x.size(); i++) - { + + for (int i : boost::irange(x.size())){ x[i] = this->gf.powTable[coefPos[i]]; } + Poly e(msg->n, nullptr); - for (int i = 0; i < x.size(); i++) - { + + for (int i : boost::irange(x.size())){ + int xi = this->gf.powTable[this->gf.characteristic - coefPos[i]]; - if (forQML) - { + + if (forQML) { emit setBelowTextTranslation(25, {""}); emit setBelowTextExtended(QString("xi = 2^(%1 - %2) = %3").arg(this->gf.characteristic).arg(coefPos[i]).arg(xi)); this->waitForQml(); } + int errLocPrime = 1; - for (int j = 0; j < x.size(); j++) - { - if (j != i) - { + + for (int j : boost::irange(x.size())) { + if (j != i) { errLocPrime = this->gf.mult(errLocPrime, 1 ^ this->gf.mult(xi, x[j])); } } - if (errLocPrime == 0) - { + + if (errLocPrime == 0) { return false; } - if (forQML) - { + + if (forQML) { emit setBelowText(QString("err_loc_prime = %1").arg(errLocPrime)); emit setBelowTextExtended(""); this->waitForQml(); } - int eval = Poly_Eval(&errEval, xi, &this->gf); - int y = this->gf.mult(x[i], eval); - if (forQML) - { + + int eval = Poly_Eval(&errEval, xi, &this->gf), + y = this->gf.mult(x[i], eval); + + if (forQML) { emit setBelowText(QString("y = 2 ^ coef_pos * error_evaluator").arg(errLocPrime)); emit setBelowTextExtended(QString("y = 2^%1 * %2").arg(x[i]).arg(eval)); this->waitForQml(); } + e.coef[errPos->at(i)] = this->gf.div(y, errLocPrime); //magnitude - if (forQML) - { + + if (forQML) { emit setBelowTextTranslation(26, {""}); - emit setBelowTextExtendedTranslation(27, {QString::number(y), " / " , QString::number(errLocPrime), " = ", QString::number(e.coef[errPos->at(i)])}); + emit setBelowTextExtendedTranslation(27, {QString::number(y), " / ", QString::number(errLocPrime), " = ", QString::number(e.coef[errPos->at(i)])}); this->waitForQml(); } } + QString tmp = msg->toString(); Poly_Add(msg, msg, &e); - if (forQML) - { + + if (forQML){ emit setBelowTextTranslation(28, {""}); emit setBelowTextExtended(QString("(%1) + (%2)").arg(e.toString()).arg(tmp)); this->waitForQml(); emit setBelowTextExtended(msg->toString()); this->waitForQml(); } + return true; } -bool ReedSolomonCode::findErrorLocator(Poly* out, Poly* synd, bool forQML) -{ - if (forQML) - { - emit setTopTextTranslation(29, {""}); - } +bool ReedSolomonCode::findErrorLocator(Poly* out, Poly* synd, bool forQML){ + if (forQML) emit setTopTextTranslation(29, {""}); + //this spits out a polynomial in reverse order but i dont know why - int init = 1; - Poly errLoc(1, &init); - Poly oldLoc(1, &init); - Poly temp; - int syndShift = 0; + int init = 1, syndShift = 0; + Poly errLoc(1, &init), oldLoc(1, &init), + temp{}; + QString d1 {}, t {}; - for (int i = nsym - 1; i >= 0; i--) - { - int K = i + syndShift; - int delta = synd->coef[K]; - for (int j = 1; j < errLoc.n; j++) - { + + for (int i = nsym - 1; i >= 0; i--){ + + int K = i + syndShift, delta = synd->coef[K]; + + for (int j = 1; j < errLoc.n; j++){ delta ^= this->gf.mult(errLoc.coef[errLoc.n - j - 1], synd->coef[K + j]); } - if (forQML) - { - if (errLoc.n <= 1) - { + + if (forQML){ + if (errLoc.n <= 1){ emit setBelowTextTranslation(30, {""}); emit setBelowTextExtended(QString("delta1 = %1").arg(delta)); } - else - { + else{ emit setBelowTextTranslation(31, {""}); emit setBelowTextExtended(QString("delta2 = %1 + %2 * %3 = %4").arg(synd->coef[K]).arg(errLoc.coef[errLoc.n - 2]).arg(synd->coef[K + 1]).arg(delta)); } + this->waitForQml(); } + Poly_Pad(&oldLoc, 0, 1); - if (delta != 0) - { - if (oldLoc.n > errLoc.n) - { + + if (delta != 0){ + if (oldLoc.n > errLoc.n){ + Poly_Scale(&temp, &oldLoc, delta, &this->gf); Poly_Scale(&oldLoc, &errLoc, this->gf.inv(delta), &this->gf); + errLoc.setCopy(temp.n, temp.coef); - if (forQML) - { + + if (forQML){ d1 = errLoc.toString(); t = oldLoc.toString(); + emit setBelowText("temp = 1/delta1"); + emit setBelowTextExtended(QString("temp = 1/%2 = %1").arg(oldLoc.toString()).arg(d1)); this->waitForQml(); } } + Poly_Scale(&temp, &oldLoc, delta, &this->gf); Poly_Add(&errLoc, &errLoc, &temp); - if (forQML && i == 0) - { + + if (forQML && i == 0){ Poly revErrLoc; + Poly_Reverse(&revErrLoc, &errLoc); + emit setBelowTextTranslation(32, {""}); emit setBelowTextExtended(QString("(%1 + %3 * %2)x + 1 = %4").arg(d1).arg(delta).arg(t).arg(revErrLoc.toString())); + this->waitForQml(); } } } + int leading = 0; + for (; errLoc.coef[leading] == 0; leading++); + Poly_Trim(&errLoc, leading, 0); + int errs = errLoc.n - 1; + out->setCopy(errLoc.n, errLoc.coef); - if (errs * 2 > nsym) - { + + if (errs * 2 > nsym){ return false; } return true; } -bool ReedSolomonCode::findErrors(std::vector* out, Poly* errLoc, int n, bool forQML) -{ - if (forQML) - { +bool ReedSolomonCode::findErrors(std::vector* out, Poly* errLoc, int n, bool forQML){ + if (forQML){ //emit setBelowText("Szukanie pozycji błędu"); emit setBelowTextTranslation(33, {""}); emit setBelowTextExtended(""); this->waitForQml(); } + int errs = errLoc->n - 1; + Poly revErrLoc; + Poly_Reverse(&revErrLoc, errLoc); Poly_ChienSearch(out, &revErrLoc, n, &this->gf, forQML); - if (out->size() != errs) - { + if (out->size() != errs){ // Too many (or few) errors found by Chien Search for the errata locator polynomial! return false; } //map to string pos - for (int i = 0; i < out->size(); i++) - { - if (out->at(i) >= n) //clearly something messed up - { + for (int i = 0; i < out->size(); i++){ + if (out->at(i) >= n){ //clearly something messed up return false; } (*out)[i] = n - out->at(i) - 1; @@ -618,231 +649,213 @@ bool ReedSolomonCode::findErrors(std::vector* out, Poly* errLoc, i return true; } -void ReedSolomonCode::forneySyndromes(Poly* out, Poly* synd, int n) -{ +void ReedSolomonCode::forneySyndromes(Poly* out, Poly* synd, int n){ Poly fsynd(synd->n - 1, synd->coef); out->setCopy(fsynd.n, fsynd.coef); } -int GaloisField::multNoLUT(int a, int b) -{ +int GaloisField::multNoLUT(int a, int b){ int ret = 0; - while (b > 0) - { + + while (b > 0){ if (b & 1) //if odd { ret ^= a; } + b >>= 1; a <<= 1; - if (a > this->characteristic) - { + + if (a > this->characteristic){ a ^= this->primitivePoly; } } + return ret; } -inline int GaloisField::mult(int a, int b) -{ +inline int GaloisField::mult(int a, int b){ return (a == 0 || b == 0) ? 0 : this->powTable[this->logTable[a] + this->logTable[b]]; } -inline int GaloisField::div(int a, int b) -{ + +inline int GaloisField::div(int a, int b){ return a == 0 ? 0 : (b == 0) ? -1 : this->powTable[this->logTable[a] - this->logTable[b] + this->characteristic]; } -inline int GaloisField::pow(int x, int power) -{ +inline int GaloisField::pow(int x, int power){ return this->powTable[(this->logTable[x] * power) % this->characteristic]; } -inline int GaloisField::inv(int x) -{ +inline int GaloisField::inv(int x){ return this->powTable[this->characteristic - this->logTable[x]]; } -inline int GaloisField::sqrt(int x) -{ +inline int GaloisField::sqrt(int x){ return logTable[x] % 2 ? this->powTable[(logTable[x] + this->characteristic) / 2] : this->powTable[logTable[x] / 2]; } -Poly::Poly() -{ +Poly::Poly(){ this->init(); } -Poly::Poly(int n, int* data) -{ +Poly::Poly(int n, int* data){ this->init(); this->setCopy(n, data); } -Poly::~Poly() -{ - if (this->coef) - { +Poly::~Poly(){ + if (this->coef){ free(this->coef); } } -void Poly::init() -{ +void Poly::init(){ this->n = 0; this->coef = nullptr; } -void Poly::setCopy(int n, int* coef) -{ - if (n > this->n) - { - if (this->coef) - { +void Poly::setCopy(int n, int* coef){ + if (n > this->n){ + if (this->coef){ free(this->coef); } this->coef = (int*)malloc(sizeof(int) * n); } + this->n = n; - if (coef) - { + + if (coef){ memcpy(this->coef, coef, sizeof(int) * n); - } else - { + } + else{ memset(this->coef, 0, sizeof(int) * n); } } -void Poly::setRef(int n, int* coef) -{ - if (this->coef) - { +void Poly::setRef(int n, int* coef){ + if (this->coef){ free(this->coef); } + this->n = n; this->coef = coef; } -QString Poly::toString() -{ +QString Poly::toString(){ return ::toString(this->coef, this->n); } - -Poly* Poly_Create(int n, int* coef) -{ +Poly* Poly_Create(int n, int* coef){ Poly* poly = (Poly*)malloc(sizeof(Poly)); + poly->init(); poly->setCopy(n, coef); + return poly; } -void Poly_Free(Poly* poly) -{ +void Poly_Free(Poly* poly){ free(poly->coef); free(poly); } -void Poly_Add(Poly* out, Poly* a, Poly* b) -{ +void Poly_Add(Poly* out, Poly* a, Poly* b){ int n = std::max(a->n, b->n); - int* temp = (int*)malloc(sizeof(int) * n); - memset(temp, 0, sizeof(int) * n); - for (int i = 0; i < a->n; i++) - { - temp[i + n - a->n] = a->coef[i]; - } - for (int i = 0; i < b->n; i++) - { - temp[i + n - b->n] ^= b->coef[i]; + std::vector temp(n, 0); + + for (auto&& [coeff_a, coeff_b] : boost::combine(boost::make_iterator_range(a->coef, a->coef + a->n), + boost::make_iterator_range(b->coef, b->coef + b->n))) { + temp.push_back(coeff_a ^ coeff_b); } - out->setRef(n, temp); + + out->setRef(n, temp.data()); } -void Poly_Scale(Poly* out, Poly* in, int scale, GaloisField* gf) -{ - if (out == in) - { - for (int i = 0; i < in->n; i++) - { +void Poly_Scale(Poly* out, Poly* in, int scale, GaloisField* gf){ + auto indices = boost::irange(0, in->n); + + if (out == in){ + for (int i : indices){ in->coef[i] = gf->mult(in->coef[i], scale); } - } else - { - int* temp = (int*)malloc(sizeof(int) * in->n); - for (int i = 0; i < in->n; i++) - { + } + else{ + std::vector temp(in->n); + + for (int i : indices){ temp[i] = gf->mult(in->coef[i], scale); } - out->setRef(in->n, temp); + + out->setRef(in->n, temp.data()); } } -void Poly_Mult(Poly* out, Poly* a, Poly* b, GaloisField* gf) -{ +void Poly_Mult(Poly* out, Poly* a, Poly* b, GaloisField* gf) { int n = a->n + b->n - 1; - int* temp = (int*)malloc(sizeof(int) * n); - memset(temp, 0, sizeof(int) * n); - for (int i = 0; i < a->n; i++) - { - for (int j = 0; j < b->n; j++) - { + std::vector temp(n, 0); + + auto indices_a = boost::irange(0, a->n), + indices_b = boost::irange(0, b->n); + + for (int i : indices_a) { + for (int j : indices_b) { temp[i + j] ^= gf->mult(a->coef[i], b->coef[j]); } } - out->setRef(n, temp); + + out->setRef(n, temp.data()); } -void Poly_Div(Poly* result, Poly* quotient, Poly* remainder, Poly* a, Poly* b, GaloisField* gf) -{ +void Poly_Div(Poly* result, Poly* quotient, Poly* remainder, Poly* a, Poly* b, GaloisField* gf){ int* temp = (int*)malloc(sizeof(int)* a->n); int normalizer = b->coef[0]; + memcpy(temp, a->coef, sizeof(int) * a->n); - for (int i = 0; i < a->n - b->n + 1; i++) - { + + for (int i = 0; i < a->n - b->n + 1; i++){ + temp[i] = gf->div(temp[i], normalizer); int coef = temp[i]; - if (coef != 0) - { - for (int j = 1; j < b->n; j++) - { - if (b->coef[j] != 0) - { + + if (coef != 0){ + for (int j = 1; j < b->n; j++){ + if (b->coef[j] != 0){ temp[i + j] ^= gf->mult(b->coef[j], coef); } } } } - if (result) - { + + if (result){ result->setCopy(a->n, temp); } + int separator = a->n - b->n + 1; - if (quotient) - { + + if (quotient){ quotient->setCopy(separator, temp); } - if (remainder) - { + + if (remainder){ remainder->setCopy(b->n - 1, temp + separator); } + free(temp); } -int Poly_Eval(Poly* poly, int x, GaloisField* gf) -{ +int Poly_Eval(Poly* poly, int x, GaloisField* gf){ int y = poly->coef[0]; - for (int i = 1; i < poly->n; i++) - { + + for (int i = 1; i < poly->n; i++){ y = gf->mult(y, x) ^ poly->coef[i]; } + return y; } -void ReedSolomonCode::Poly_ChienSearch(std::vector* out, Poly* poly, int max, GaloisField* gf, bool forQML) -{ - if (forQML) - { +void ReedSolomonCode::Poly_ChienSearch(std::vector* out, Poly* poly, int max, GaloisField* gf, bool forQML){ + if (forQML){ emit setTopTextTranslation(33, {""}); emit setBelowTextTranslation(34, {""}); } @@ -850,20 +863,22 @@ void ReedSolomonCode::Poly_ChienSearch(std::vector* out, Poly* pol //this seems unnecessary because all multiplications are performed via lookup table anyway int* temp = (int*)malloc(sizeof(int)* poly->n); memcpy(temp, poly->coef, sizeof(int) * poly->n); - for (int i = 0; i < max; i++) - { + + for (int i = 0; i < max; i++){ + int eval = Poly_Eval(poly, gf->powTable[i], gf); - if (eval == 0) - { + + if (eval == 0){ out->push_back(i); } - if (forQML) - { + + if (forQML){ + emit setBelowTextTranslation(35, {QString::number(i)}); emit setBelowTextExtended(QString("(%1)(%2) = %3").arg(poly->toString()).arg(gf->powTable[i]).arg(eval)); this->waitForQml(); - if (eval == 0) - { + + if (eval == 0){ emit setBelowTextTranslation(36, {QString::number(i)}); emit setBelowTextExtended(QString("%1 - %2 = %3").arg(max).arg(i).arg(max - i)); this->waitForQml(); @@ -885,44 +900,46 @@ void ReedSolomonCode::Poly_ChienSearch(std::vector* out, Poly* pol free(temp); } -void Poly_Pad(Poly* poly, int left, int right) -{ +void Poly_Pad(Poly* poly, int left, int right){ int n = poly->n + left + right; int* temp = (int*)malloc(sizeof(int)* n); + memset(temp, 0, sizeof(int) * left); memcpy(temp + left, poly->coef, sizeof(int) * poly->n); memset(temp + (left + poly->n), 0, sizeof(int) * right); + poly->setRef(n, temp); } -void Poly_Trim(Poly* poly, int left, int right) -{ +void Poly_Trim(Poly* poly, int left, int right){ int n = poly->n - left - right; int* temp = (int*)malloc(sizeof(int)* n); + memcpy(temp, poly->coef + left, sizeof(int) * n); + poly->setRef(n, temp); } -void Poly_Append(Poly* out, Poly* a, Poly* b) -{ +void Poly_Append(Poly* out, Poly* a, Poly* b){ int n = a->n + b->n; int* temp = (int*)malloc(sizeof(int)* n); + memcpy(temp, a->coef, sizeof(int)* a->n); memcpy(temp + a->n, b->coef, sizeof(int)* b->n); + out->setRef(n, temp); } -void Poly_Reverse(Poly* out, Poly* in) -{ +void Poly_Reverse(Poly* out, Poly* in){ int* temp = (int*)malloc(sizeof(int)* in->n); - for (int i = 0; i < in->n; i++) - { + + for (int i = 0; i < in->n; i++){ temp[i] = in->coef[in->n - i - 1]; } + out->setRef(in->n, temp); } - unsigned int primes[] = { PRIM(0), PRIM(1), PRIM(2), PRIM(3), PRIM(4), PRIM(5), PRIM(6), PRIM(7), @@ -934,36 +951,35 @@ unsigned int primes[] = { PRIM(28), PRIM(29), PRIM(30), PRIM(31) }; -GaloisField::GaloisField(int fieldPower) -{ +GaloisField::GaloisField(int fieldPower){ this->characteristic = ((int)1 << fieldPower) - 1; this->fieldPower = fieldPower; this->primitivePoly = primes[fieldPower]; + //init the tables unsigned int val = 1; this->powTable = (int*)malloc(sizeof(int) * this->characteristic * 2); this->logTable = (int*)malloc(sizeof(int) * (this->characteristic + 1)); + powTable[0] = val; logTable[0] = 0; logTable[1] = 0; - for (int i = 1; i < this->characteristic; i++) - { + + for (int i = 1; i < this->characteristic; i++){ val <<= 1; - if (val > this->characteristic) - { + if (val > this->characteristic){ val ^= this->primitivePoly; } powTable[i] = (int)val; logTable[(int)val] = i; } - for (int i = this->characteristic; i < this->characteristic * 2; i++) - { + + for (int i = this->characteristic; i < this->characteristic * 2; i++){ powTable[i] = powTable[i - this->characteristic]; } } -GaloisField::~GaloisField() -{ +GaloisField::~GaloisField(){ free(this->powTable); free(this->logTable); } diff --git a/source_gui/FormComponents/VisualizeCheckbox.qml b/source_gui/FormComponents/VisualizeCheckbox.qml index 54a6a14..78a492d 100644 --- a/source_gui/FormComponents/VisualizeCheckbox.qml +++ b/source_gui/FormComponents/VisualizeCheckbox.qml @@ -15,8 +15,8 @@ CheckBox{ Text { width: 10 height: 10 - x: 1 - y: -3 + x: -2 + y: -6 text: "✔" font.pointSize: 18 color: parent.parent.down ? "#17a81a" : "#21be2b"