public void Encode(int[] toEncode, int ecBytes) { if (ecBytes == 0) { throw new ArgumentException("No error correction bytes"); } int dataBytes = toEncode.Length - ecBytes; if (dataBytes <= 0) { throw new ArgumentException("No data bytes provided"); } GenericGFPoly generator = BuildGenerator(ecBytes); var infoCoefficients = new int[dataBytes]; Array.Copy(toEncode, 0, infoCoefficients, 0, dataBytes); var info = new GenericGFPoly(field, infoCoefficients); info = info.MultiplyByMonomial(ecBytes, 1); GenericGFPoly remainder = info.Divide(generator)[1]; int[] coefficients = remainder.Coefficients; int numZeroCoefficients = ecBytes - coefficients.Length; for (var i = 0; i < numZeroCoefficients; i++) { toEncode[dataBytes + i] = 0; } Array.Copy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.Length); }
// this method has been added by Sebastien ROBERT // this implementation makes the mathematician-friendly approach programmer-friendly public byte[] EncodeEx(byte[] toEncode, int ecBytes) { if (ecBytes == 0) { throw new ArgumentException("No error correction bytes"); } int dataBytes = toEncode.Length - ecBytes; if (dataBytes <= 0) { throw new ArgumentException("No data bytes provided"); } GenericGFPoly generator = BuildGenerator(ecBytes); int[] infoCoefficients = toEncode.Select(x => (int)x).ToArray(); var info = new GenericGFPoly(field, infoCoefficients); info = info.MultiplyByMonomial(ecBytes, 1); GenericGFPoly remainder = info.Divide(generator)[1]; int[] coefficients = remainder.Coefficients; int numZeroCoefficients = ecBytes - coefficients.Length; return(Enumerable.Repeat <byte>(0, numZeroCoefficients) .Concat(coefficients.Select(x => (byte)x)) .ToArray()); }
internal GenericGFPoly[] Divide(GenericGFPoly other) { if (field.Equals(other.field) == false) { throw new ArgumentException("GenericGFPolys do not have same GenericGF field"); } if (other.IsZero) { throw new ArgumentException("Divide by 0"); } GenericGFPoly quotient = field.Zero; GenericGFPoly remainder = this; int denominatorLeadingTerm = other.GetCoefficient(other.Degree); int inverseDenominatorLeadingTerm = field.Inverse(denominatorLeadingTerm); while (remainder.Degree >= other.Degree && !remainder.IsZero) { int degreeDifference = remainder.Degree - other.Degree; int scale = field.Multiply(remainder.GetCoefficient(remainder.Degree), inverseDenominatorLeadingTerm); GenericGFPoly term = other.MultiplyByMonomial(degreeDifference, scale); GenericGFPoly iterationQuotient = field.BuildMonomial(degreeDifference, scale); quotient = quotient.AddOrSubtract(iterationQuotient); remainder = remainder.AddOrSubtract(term); } return(new GenericGFPoly[] { quotient, remainder }); }
private int[] FindErrorLocations(GenericGFPoly errorLocator) { // This is a direct application of Chien's search int numErrors = errorLocator.Degree; if (numErrors == 1) { // shortcut return(new int[] { errorLocator.GetCoefficient(1) }); } int[] result = new int[numErrors]; int e = 0; for (int i = 1; i < field.Size && e < numErrors; i++) { if (errorLocator.EvaluateAt(i) == 0) { result[e] = field.Inverse(i); e++; } } if (e != numErrors) { // throw new ReedSolomonException("Error locator degree does not match number of roots"); return(null); } return(result); }
internal GenericGFPoly Multiply(GenericGFPoly other) { if (field.Equals(other.field) == false) { throw new ArgumentException("GenericGFPolys do not have same GenericGF field"); } if (IsZero || other.IsZero) { return(field.Zero); } int[] aCoefficients = coefficients; int aLength = aCoefficients.Length; int[] bCoefficients = other.coefficients; int bLength = bCoefficients.Length; int[] product = new int[aLength + bLength - 1]; for (int i = 0; i < aLength; i++) { int aCoeff = aCoefficients[i]; for (int j = 0; j < bLength; j++) { product[i + j] = GenericGF.AddOrSubtract(product[i + j], field.Multiply(aCoeff, bCoefficients[j])); } } return(new GenericGFPoly(field, product)); }
private void Initialize() { expTable = new int[size]; logTable = new int[size]; int x = 1; for (int i = 0; i < size; i++) { expTable[i] = x; x <<= 1; // x = x * 2; we're assuming the generator alpha is 2 if (x >= size) { x ^= primitive; x &= size - 1; } } for (int i = 0; i < size - 1; i++) { logTable[expTable[i]] = i; } // logTable[0] == 0 but this should never be used zero = new GenericGFPoly(this, new int[] { 0 }); one = new GenericGFPoly(this, new int[] { 1 }); initialized = true; }
/// <summary> /// <p>Decodes given set of received codewords, which include both data and error-correction /// codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place, /// in the input.</p> /// </summary> /// <param name="received">data and error-correction codewords</param> /// <param name="twoS">number of error-correction codewords available</param> /// <returns>false: decoding fails</returns> public bool Decode(int[] received, int twoS) { var poly = new GenericGFPoly(field, received); var syndromeCoefficients = new int[twoS]; var noError = true; for (var i = 0; i < twoS; i++) { int eval = poly.EvaluateAt(field.Exp(i + field.GeneratorBase)); syndromeCoefficients[syndromeCoefficients.Length - 1 - i] = eval; if (eval != 0) { noError = false; } } if (noError) { return(true); } var syndrome = new GenericGFPoly(field, syndromeCoefficients); GenericGFPoly[] sigmaOmega = RunEuclideanAlgorithm(field.BuildMonomial(twoS, 1), syndrome, twoS); if (sigmaOmega == null) { return(false); } GenericGFPoly sigma = sigmaOmega[0]; int[] errorLocations = FindErrorLocations(sigma); if (errorLocations == null) { return(false); } GenericGFPoly omega = sigmaOmega[1]; int[] errorMagnitudes = FindErrorMagnitudes(omega, errorLocations); for (int i = 0; i < errorLocations.Length; i++) { int position = received.Length - 1 - field.Log(errorLocations[i]); if (position < 0) { // throw new ReedSolomonException("Bad error location"); return(false); } received[position] = GenericGF.AddOrSubtract(received[position], errorMagnitudes[i]); } return(true); }
private GenericGFPoly BuildGenerator(int degree) { if (degree >= cachedGenerators.Count) { GenericGFPoly lastGenerator = cachedGenerators[cachedGenerators.Count - 1]; for (int d = cachedGenerators.Count; d <= degree; d++) { var nextGenerator = lastGenerator.Multiply(new GenericGFPoly(field, new int[] { 1, field.Exp(d - 1 + field.GeneratorBase) })); cachedGenerators.Add(nextGenerator); lastGenerator = nextGenerator; } } return(cachedGenerators[degree]); }
internal GenericGFPoly AddOrSubtract(GenericGFPoly other) { if (field.Equals(other.field) == false) { throw new ArgumentException("GenericGFPolys do not have same GenericGF field"); } if (IsZero) { return(other); } if (other.IsZero) { return(this); } int[] smallerCoefficients = coefficients; int[] largerCoefficients = other.coefficients; if (smallerCoefficients.Length > largerCoefficients.Length) { int[] temp = smallerCoefficients; smallerCoefficients = largerCoefficients; largerCoefficients = temp; } int[] sumDiff = new int[largerCoefficients.Length]; int lengthDiff = largerCoefficients.Length - smallerCoefficients.Length; // Copy high-order terms only found in higher-degree polynomial's coefficients Array.Copy(largerCoefficients, 0, sumDiff, 0, lengthDiff); for (int i = lengthDiff; i < largerCoefficients.Length; i++) { sumDiff[i] = GenericGF.AddOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); } return(new GenericGFPoly(field, sumDiff)); }
private int[] FindErrorMagnitudes(GenericGFPoly errorEvaluator, int[] errorLocations) { // This is directly applying Forney's Formula int s = errorLocations.Length; int[] result = new int[s]; for (int i = 0; i < s; i++) { int xiInverse = field.Inverse(errorLocations[i]); int denominator = 1; for (int j = 0; j < s; j++) { if (i != j) { //denominator = field.multiply(denominator, // GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))); // Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug. // Below is a funny-looking workaround from Steven Parkes int term = field.Multiply(errorLocations[j], xiInverse); int termPlus1 = (term & 0x1) == 0 ? term | 1 : term & ~1; denominator = field.Multiply(denominator, termPlus1); // removed in java version, not sure if this is right // denominator = field.multiply(denominator, GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))); } } result[i] = field.Multiply(errorEvaluator.EvaluateAt(xiInverse), field.Inverse(denominator)); if (field.GeneratorBase != 0) { result[i] = field.Multiply(result[i], xiInverse); } } return(result); }
internal GenericGFPoly[] RunEuclideanAlgorithm(GenericGFPoly a, GenericGFPoly b, int R) { // Assume a's degree is >= b's if (a.Degree < b.Degree) { GenericGFPoly temp = a; a = b; b = temp; } GenericGFPoly rLast = a; GenericGFPoly r = b; GenericGFPoly tLast = field.Zero; GenericGFPoly t = field.One; int halfR = R / 2; // Run Euclidean algorithm until r's degree is less than R/2 while (r.Degree >= halfR) { GenericGFPoly rLastLast = rLast; GenericGFPoly tLastLast = tLast; rLast = r; tLast = t; // Divide rLastLast by rLast, with quotient in q and remainder in r if (rLast.IsZero) { // Oops, Euclidean algorithm already terminated? // throw new ReedSolomonException("r_{i-1} was zero"); return(null); } r = rLastLast; GenericGFPoly q = field.Zero; int denominatorLeadingTerm = rLast.GetCoefficient(rLast.Degree); int dltInverse = field.Inverse(denominatorLeadingTerm); while (r.Degree >= rLast.Degree && !r.IsZero) { int degreeDiff = r.Degree - rLast.Degree; int scale = field.Multiply(r.GetCoefficient(r.Degree), dltInverse); q = q.AddOrSubtract(field.BuildMonomial(degreeDiff, scale)); r = r.AddOrSubtract(rLast.MultiplyByMonomial(degreeDiff, scale)); } t = q.Multiply(tLast).AddOrSubtract(tLastLast); if (r.Degree >= rLast.Degree) { // throw new IllegalStateException("Division algorithm failed to reduce polynomial?"); return(null); } } int sigmaTildeAtZero = t.GetCoefficient(0); if (sigmaTildeAtZero == 0) { // throw new ReedSolomonException("sigmaTilde(0) was zero"); return(null); } int inverse = field.Inverse(sigmaTildeAtZero); GenericGFPoly sigma = t.Multiply(inverse); GenericGFPoly omega = r.Multiply(inverse); return(new GenericGFPoly[] { sigma, omega }); }