-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bugs and errors in recovering with erasures #3
Comments
I've found a bug in your test: bool DecodeResult = RSD.Decode(TestData2, CodeSize, KnownErrors ? TestErrPos.ToArray() : null); The Your test incorrectly assumes all the introduced errors are in fact correctable. When I modified the test so it keeps track of the So, in those cases your test incorrectly assumes the input and output should match, while they in fact are expected to be different in those cases. |
Let's assume, that data consists of In provided example, I understood, that Reed-Solomon code can work in one of two ways:
Let's focus on the second RS code working way. The single test is following:
I assume, that every test case accords to fundamental restoring requirement - the number of erasures are less or equal to code elements and erasure list is provided. Why Reed-Solomon code does not restore original values in some cases regardless meeting the fundamental requirement? Is there some additional restoring requirement, which is not included in the test code? |
I've now found the real bug, again, in your test: This part: while (TestErr > 0)
{
int P = R.Next(DataSize - 1);
if (!TestErrPos.Contains(P))
{
TestErrPos.Add(P);
int D = R.Next(ValMax);
if (TestData2[P] != D)
{
TestData2[P] = D;
TestData3[P] = D;
TestErr--;
}
}
} Should look like this: while (TestErr > 0)
{
int P = R.Next(DataSize - 1);
if (!TestErrPos.Contains(P))
{
int D = R.Next(ValMax);
if (TestData2[P] != D)
{
TestErrPos.Add(P);
TestData2[P] = D;
TestData3[P] = D;
TestErr--;
}
}
} You are adding the position to the list too early, this causes good non-corrupted values to be flagged as bad. In the line With the erasure list two things are very important:
|
Before reading your answer, I found the same bug in my code and I splitted generating corruption into two explicit steps:
Your bugfix suggestion will give the same result. The bug caused important requirement violation: The number of provided indices could exceed The whole test code are following, I ran the code once, it took long time and all test cases passed. using System;
using System.Collections.Generic;
namespace ReedSolomonTest
{
class MainClass
{
/// <summary>
/// Creating Galois field
/// </summary>
/// <returns>The GenericGF object</returns>
static STH1123.ReedSolomon.GenericGF GenGF(int NumOfBits)
{
int PrimPoly = 0;
switch (NumOfBits)
{
case 2: PrimPoly = 4 + 2 + 1; break;
case 3: PrimPoly = 8 + 2 + 1; break;
case 4: PrimPoly = 16 + 2 + 1; break;
case 5: PrimPoly = 32 + 4 + 1; break;
case 6: PrimPoly = 64 + 2 + 1; break;
case 7: PrimPoly = 128 + 2 + 1; break;
case 8: PrimPoly = 256 + 16 + 8 + 4 + 1; break;
case 9: PrimPoly = 512 + 16 + 1; break;
case 10: PrimPoly = 1024 + 8 + 1; break;
case 11: PrimPoly = 2048 + 4 + 1; break;
case 12: PrimPoly = 4096 + 64 + 16 + 2 + 1; break;
case 13: PrimPoly = 8192 + 16 + 8 + 2 + 1; break;
case 14: PrimPoly = 16384 + 32 + 8 + 2 + 1; break;
case 15: PrimPoly = 32768 + 2 + 1; break;
case 16: PrimPoly = 65536 + 32 + 8 + 4 + 1; break;
case 17: PrimPoly = 131072 + 8 + 1; break;
case 18: PrimPoly = 262144 + 32 + 4 + 2 + 1; break;
case 19: PrimPoly = 524288 + 32 + 4 + 2 + 1; break;
case 20: PrimPoly = 1048576 + 8 + 1; break;
case 21: PrimPoly = 2097152 + 4 + 1; break;
case 22: PrimPoly = 4194304 + 2 + 1; break;
case 23: PrimPoly = 8388608 + 32 + 1; break;
case 24: PrimPoly = 16777216 + 16 + 8 + 2 + 1; break;
case 25: PrimPoly = 33554432 + 8 + 1; break;
case 26: PrimPoly = 67108864 + 64 + 4 + 2 + 1; break;
case 27: PrimPoly = 134217728 + 32 + 4 + 2 + 1; break;
case 28: PrimPoly = 268435456 + 8 + 1; break;
case 29: PrimPoly = 536870912 + 4 + 1; break;
case 30: PrimPoly = 1073741824 + 64 + 16 + 2 + 1; break;
default: throw new Exception("Unsupported number of bits");
}
return new STH1123.ReedSolomon.GenericGF(PrimPoly, (int)Math.Pow(2, NumOfBits), 1);
}
public static void Main(string[] args)
{
// Number of bits per symbol
int NumOfBits = 8;
// Raw data block size
int DataSize = 223;
// Reed-Solomon code block size
int CodeSize = 32;
// Maximum value of element (2^n)-1, where n=1,2,3...
int ValMax = ((int)Math.Pow(2, NumOfBits) - 1);
// Number of randomly generated errors
int TestErrCount = 31;
// Determine if error locations is known
bool KnownErrors = true;
// Data structure with correction code
int[] TestData1 = new int[DataSize + CodeSize];
int[] TestData2 = new int[DataSize + CodeSize];
int[] TestData3 = new int[DataSize + CodeSize];
// Creating pseudo-random number generator
Random R = new Random();
// Maximum used value
long MaxCodeVal = 0;
// Good and bad result counter
int ResultGood = 0;
int ResultBad = 0;
int ResultFalse = 0;
int ResultFailure = 0;
// Number of test iterations
int TestIterations = 1000000;
// Iterative repeat test
for (int TestI = 0; TestI < TestIterations; TestI++)
{
// Clearing data
for (int i = 0; i < (DataSize + CodeSize); i++)
{
TestData1[i] = 0;
TestData2[i] = 0;
TestData3[i] = 0;
}
// Creating three instances of the same raw data
for (int i = 0; i < DataSize; i++)
{
TestData1[i] = R.Next(0, ValMax);
TestData2[i] = TestData1[i];
TestData3[i] = TestData1[i];
}
// Encoding
STH1123.ReedSolomon.ReedSolomonEncoder RSE = new STH1123.ReedSolomon.ReedSolomonEncoder(GenGF(NumOfBits));
RSE.Encode(TestData2, CodeSize);
// Making erasure/error list of indices
int TestErr = TestErrCount;
List<int> TestErrPos = new List<int>();
while (TestErr > 0)
{
int P = R.Next(DataSize - 1);
if (!TestErrPos.Contains(P))
{
TestErrPos.Add(P);
TestErr--;
}
}
// Change value of errornous elements
foreach (int item in TestErrPos)
{
int V = TestData2[item];
while (TestData2[item] == V)
{
V = R.Next(ValMax);
}
TestData2[item] = V;
TestData3[item] = V;
}
// Trying to recovery original data
STH1123.ReedSolomon.ReedSolomonDecoder RSD = new STH1123.ReedSolomon.ReedSolomonDecoder(GenGF(NumOfBits));
bool DecodeResult = RSD.Decode(TestData2, CodeSize, KnownErrors ? TestErrPos.ToArray() : null);
if (DecodeResult)
{
// Encounting differences in raw data instances
int Diff12 = 0;
int Diff13 = 0;
for (int i = 0; i < DataSize; i++)
{
if (TestData1[i] != TestData2[i])
{
Diff12++;
}
if (TestData1[i] != TestData3[i])
{
Diff13++;
}
}
// Reading the maximum value
for (int i = 0; i < (DataSize + CodeSize); i++)
{
if (MaxCodeVal < TestData2[i])
{
MaxCodeVal = TestData2[i];
}
}
// If there is not difference, this test result is good,
// otherwise the test result is bad
if (Diff13 == TestErrCount)
{
if (Diff12 == 0)
{
ResultGood++;
}
else
{
ResultBad++;
}
}
else
{
ResultFailure++;
}
}
else
{
ResultFalse++;
}
// Printing the test progress
if ((TestIterations / 100) > 0)
{
if ((TestI % (TestIterations / 100)) == 0)
{
Console.WriteLine("Progress: " + (TestI / (TestIterations / 100)) + "%");
}
}
else
{
Console.WriteLine("Progress: " + TestI + "/" + TestIterations);
}
}
// Printing the test results
Console.WriteLine("Maximum existing value: " + MaxCodeVal.ToString());
Console.WriteLine("Good: " + ResultGood);
Console.WriteLine("Bad: " + ResultBad);
Console.WriteLine("False: " + ResultFalse);
Console.WriteLine("Failed: " + ResultFailure);
Console.WriteLine("Total: " + (ResultFalse + ResultGood + ResultBad + ResultFailure));
Console.ReadLine();
}
}
} I tested with a few another data sizes, code sizes and number of bits. in every case all tests passed, so I assume, that the issue is solved now. |
I recently read, that there is third way of Reed-Solomon code working: How I have to understand this information?
I ran the test code with following parameters: int NumOfBits = 4;
int DataSize = 10;
int CodeSize = 4;
int TestErrCount = 4;
bool KnownErrors = false; The I changed value size to 8 bits, other parameters are the same: int NumOfBits = 8;
int DataSize = 10;
int CodeSize = 4;
int TestErrCount = 4;
bool KnownErrors = false; In this case, about 1/1000 of test cases as Now, I extended the data and code sizes: int NumOfBits = 8;
int DataSize = 223;
int CodeSize = 32;
int TestErrCount = 32;
bool KnownErrors = false; In the above parameters, the test took much more time, but all cases returned false as I expected. The test conclusion seems be: If the number of erroneous values are equal to |
I have tested the library by creating random data, corrupting the data and trying to recovery. I use the v2.1.0 release.
If I try to recovery using known error locations (erasures) thousand times, sometimes recovery fails. Below there is simple console application code, which indicates the problem:
The text was updated successfully, but these errors were encountered: