reedsolomon format

This commit is contained in:
Henry Schimke
2022-08-23 13:24:33 -05:00
parent 4297b494c2
commit 7fbe7cabf1

View File

@@ -78,7 +78,6 @@ pub const MAXICODE_FIELD_64:GenericGF = AZTEC_DATA_6;
* @author David Olivier * @author David Olivier
*/ */
pub struct GenericGF { pub struct GenericGF {
expTable: Vec<usize>, expTable: Vec<usize>,
logTable: Vec<usize>, logTable: Vec<usize>,
zero: Box<GenericGFPoly>, zero: Box<GenericGFPoly>,
@@ -101,7 +100,6 @@ impl PartialEq for GenericGF {
impl Eq for GenericGF {} impl Eq for GenericGF {}
impl GenericGF { impl GenericGF {
/** /**
* Create a representation of GF(size) using the given primitive polynomial. * Create a representation of GF(size) using the given primitive polynomial.
* *
@@ -116,7 +114,6 @@ impl GenericGF{
pub fn new(primitive: usize, size: usize, b: usize) -> Self { pub fn new(primitive: usize, size: usize, b: usize) -> Self {
let mut new_ggf: Self; let mut new_ggf: Self;
new_ggf.primitive = primitive; new_ggf.primitive = primitive;
new_ggf.size = size; new_ggf.size = size;
new_ggf.generatorBase = b; new_ggf.generatorBase = b;
@@ -219,7 +216,6 @@ impl GenericGF{
pub fn getGeneratorBase(&self) -> usize { pub fn getGeneratorBase(&self) -> usize {
return self.generatorBase; return self.generatorBase;
} }
} }
impl fmt::Display for GenericGF { impl fmt::Display for GenericGF {
@@ -228,7 +224,6 @@ impl fmt::Display for GenericGF {
} }
} }
/* /*
* Copyright 2007 ZXing authors * Copyright 2007 ZXing authors
* *
@@ -257,10 +252,8 @@ impl fmt::Display for GenericGF {
* @author Sean Owen * @author Sean Owen
*/ */
pub struct GenericGFPoly { pub struct GenericGFPoly {
field: Box<GenericGF>, field: Box<GenericGF>,
coefficients: Vec<usize>, coefficients: Vec<usize>,
} }
impl GenericGFPoly { impl GenericGFPoly {
@@ -273,7 +266,10 @@ impl GenericGFPoly {
* or if leading coefficient is 0 and this is not a * or if leading coefficient is 0 and this is not a
* constant polynomial (that is, it is not the monomial "0") * constant polynomial (that is, it is not the monomial "0")
*/ */
pub fn new( field :Box<GenericGF>, coefficients: &Vec<usize>) -> Result<Self,IllegalArgumentException> { pub fn new(
field: Box<GenericGF>,
coefficients: &Vec<usize>,
) -> Result<Self, IllegalArgumentException> {
if (coefficients.len() == 0) { if (coefficients.len() == 0) {
return Err(IllegalArgumentException::new("")); return Err(IllegalArgumentException::new(""));
} }
@@ -290,9 +286,10 @@ impl GenericGFPoly {
if (firstNonZero == coefficientsLength) { if (firstNonZero == coefficientsLength) {
vec![0] vec![0]
} else { } else {
let mut new_coefficients =
let mut new_coefficients = Vec::with_capacity(coefficientsLength - firstNonZero); Vec::with_capacity(coefficientsLength - firstNonZero);
new_coefficients[0..new_coefficients.len()].clone_from_slice(&coefficients[firstNonZero..new_coefficients.len()]); new_coefficients[0..new_coefficients.len()]
.clone_from_slice(&coefficients[firstNonZero..new_coefficients.len()]);
// System.arraycopy(coefficients, // System.arraycopy(coefficients,
// firstNonZero, // firstNonZero,
// this.coefficients, // this.coefficients,
@@ -353,14 +350,25 @@ impl GenericGFPoly {
let size = self.coefficients.len(); let size = self.coefficients.len();
for i in 1..size { for i in 1..size {
//for (int i = 1; i < size; i++) { //for (int i = 1; i < size; i++) {
result = GenericGF::addOrSubtract(self.field.multiply(a, result.try_into().unwrap()).try_into().unwrap(), self.coefficients[i]); result = GenericGF::addOrSubtract(
self.field
.multiply(a, result.try_into().unwrap())
.try_into()
.unwrap(),
self.coefficients[i],
);
} }
return result; return result;
} }
pub fn addOrSubtract(&self, other:Box<GenericGFPoly>) -> Result<Box<GenericGFPoly>,IllegalArgumentException>{ pub fn addOrSubtract(
&self,
other: Box<GenericGFPoly>,
) -> Result<Box<GenericGFPoly>, IllegalArgumentException> {
if self.field != other.field { if self.field != other.field {
return Err(IllegalArgumentException::new("GenericGFPolys do not have same GenericGF field")); return Err(IllegalArgumentException::new(
"GenericGFPolys do not have same GenericGF field",
));
} }
if (self.isZero()) { if (self.isZero()) {
return Ok(other); return Ok(other);
@@ -385,16 +393,24 @@ impl GenericGFPoly {
for i in lengthDiff..largerCoefficients.len() { for i in lengthDiff..largerCoefficients.len() {
//for (int i = lengthDiff; i < largerCoefficients.length; i++) { //for (int i = lengthDiff; i < largerCoefficients.length; i++) {
sumDiff[i] = GenericGF::addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); sumDiff[i] = GenericGF::addOrSubtract(
smallerCoefficients[i - lengthDiff],
largerCoefficients[i],
);
} }
return Ok(Box::new(GenericGFPoly::new(self.field, &sumDiff)?)); return Ok(Box::new(GenericGFPoly::new(self.field, &sumDiff)?));
} }
pub fn multiply(&self, other:&GenericGFPoly) -> Result<Box<GenericGFPoly>,IllegalArgumentException> { pub fn multiply(
&self,
other: &GenericGFPoly,
) -> Result<Box<GenericGFPoly>, IllegalArgumentException> {
if self.field != other.field { if self.field != other.field {
//if (!field.equals(other.field)) { //if (!field.equals(other.field)) {
return Err( IllegalArgumentException::new("GenericGFPolys do not have same GenericGF field")); return Err(IllegalArgumentException::new(
"GenericGFPolys do not have same GenericGF field",
));
} }
if (self.isZero() || other.isZero()) { if (self.isZero() || other.isZero()) {
return Ok(self.field.getZero()); return Ok(self.field.getZero());
@@ -409,8 +425,16 @@ impl GenericGFPoly {
let aCoeff = aCoefficients[i]; let aCoeff = aCoefficients[i];
for j in 0..bLength { for j in 0..bLength {
//for (int j = 0; j < bLength; j++) { //for (int j = 0; j < bLength; j++) {
product[i + j] = GenericGF::addOrSubtract(product[i + j], product[i + j] = GenericGF::addOrSubtract(
self.field.multiply(aCoeff.try_into().unwrap(), bCoefficients[j].try_into().unwrap()).try_into().unwrap()); product[i + j],
self.field
.multiply(
aCoeff.try_into().unwrap(),
bCoefficients[j].try_into().unwrap(),
)
.try_into()
.unwrap(),
);
} }
} }
return Ok(Box::new(GenericGFPoly::new(self.field, &product)?)); return Ok(Box::new(GenericGFPoly::new(self.field, &product)?));
@@ -433,7 +457,11 @@ impl GenericGFPoly {
return Box::new(GenericGFPoly::new(self.field, &product).unwrap()); return Box::new(GenericGFPoly::new(self.field, &product).unwrap());
} }
pub fn multiplyByMonomial(&self, degree:usize, coefficient:usize) -> Result<Box<GenericGFPoly>,IllegalArgumentException> { pub fn multiplyByMonomial(
&self,
degree: usize,
coefficient: usize,
) -> Result<Box<GenericGFPoly>, IllegalArgumentException> {
if (degree < 0) { if (degree < 0) {
return Err(IllegalArgumentException::new("")); return Err(IllegalArgumentException::new(""));
} }
@@ -449,10 +477,15 @@ impl GenericGFPoly {
return Ok(Box::new(GenericGFPoly::new(self.field, &product)?)); return Ok(Box::new(GenericGFPoly::new(self.field, &product)?));
} }
pub fn divide(&self, other:&GenericGFPoly) -> Result<Vec<Box<GenericGFPoly>>,IllegalArgumentException>{ pub fn divide(
&self,
other: &GenericGFPoly,
) -> Result<Vec<Box<GenericGFPoly>>, IllegalArgumentException> {
if self.field != other.field { if self.field != other.field {
//if (!field.equals(other.field)) { //if (!field.equals(other.field)) {
return Err( IllegalArgumentException::new("GenericGFPolys do not have same GenericGF field")); return Err(IllegalArgumentException::new(
"GenericGFPolys do not have same GenericGF field",
));
} }
if (other.isZero()) { if (other.isZero()) {
return Err(IllegalArgumentException::new("Divide by 0")); return Err(IllegalArgumentException::new("Divide by 0"));
@@ -469,7 +502,10 @@ impl GenericGFPoly {
while (remainder.getDegree() >= other.getDegree() && !remainder.isZero()) { while (remainder.getDegree() >= other.getDegree() && !remainder.isZero()) {
let degreeDifference = remainder.getDegree() - other.getDegree(); let degreeDifference = remainder.getDegree() - other.getDegree();
let scale = self.field.multiply(remainder.getCoefficient(remainder.getDegree()), inverseDenominatorLeadingTerm); let scale = self.field.multiply(
remainder.getCoefficient(remainder.getDegree()),
inverseDenominatorLeadingTerm,
);
let term = other.multiplyByMonomial(degreeDifference, scale)?; let term = other.multiplyByMonomial(degreeDifference, scale)?;
let iterationQuotient = self.field.buildMonomial(degreeDifference, scale); let iterationQuotient = self.field.buildMonomial(degreeDifference, scale);
quotient = quotient.addOrSubtract(iterationQuotient)?; quotient = quotient.addOrSubtract(iterationQuotient)?;
@@ -478,7 +514,6 @@ impl GenericGFPoly {
return Ok(vec![quotient, Box::new(*remainder)]); return Ok(vec![quotient, Box::new(*remainder)]);
} }
} }
impl fmt::Display for GenericGFPoly { impl fmt::Display for GenericGFPoly {
@@ -569,14 +604,14 @@ impl fmt::Display for GenericGFPoly {
* @author sanfordsquires * @author sanfordsquires
*/ */
pub struct ReedSolomonDecoder { pub struct ReedSolomonDecoder {
field: Box<GenericGF>, field: Box<GenericGF>,
} }
impl ReedSolomonDecoder { impl ReedSolomonDecoder {
pub fn new(field: GenericGF) -> Self { pub fn new(field: GenericGF) -> Self {
Self { field: Box::new(field) } Self {
field: Box::new(field),
}
} }
/** /**
@@ -588,13 +623,19 @@ impl ReedSolomonDecoder{
* @param twoS number of error-correction codewords available * @param twoS number of error-correction codewords available
* @throws ReedSolomonException if decoding fails for any reason * @throws ReedSolomonException if decoding fails for any reason
*/ */
pub fn decode( &self,received: &mut Vec<usize>, twoS:usize) -> Result<(),ReedSolomonException> { pub fn decode(
&self,
received: &mut Vec<usize>,
twoS: usize,
) -> Result<(), ReedSolomonException> {
let poly = GenericGFPoly::new(self.field, received); let poly = GenericGFPoly::new(self.field, received);
let syndromeCoefficients = Vec::with_capacity(twoS); let syndromeCoefficients = Vec::with_capacity(twoS);
let mut noError = true; let mut noError = true;
for i in 0..twoS { for i in 0..twoS {
//for (int i = 0; i < twoS; i++) { //for (int i = 0; i < twoS; i++) {
let eval = poly.unwrap().evaluateAt(self.field.exp(i + self.field.getGeneratorBase())); let eval = poly
.unwrap()
.evaluateAt(self.field.exp(i + self.field.getGeneratorBase()));
syndromeCoefficients[syndromeCoefficients.len() - 1 - i] = eval; syndromeCoefficients[syndromeCoefficients.len() - 1 - i] = eval;
if (eval != 0) { if (eval != 0) {
noError = false; noError = false;
@@ -605,7 +646,7 @@ impl ReedSolomonDecoder{
} }
let syndrome = match GenericGFPoly::new(self.field, &syndromeCoefficients) { let syndrome = match GenericGFPoly::new(self.field, &syndromeCoefficients) {
Ok(res) => res, Ok(res) => res,
Err(fail) => return Err(ReedSolomonException::new("IllegalArgumentException")) Err(fail) => return Err(ReedSolomonException::new("IllegalArgumentException")),
}; };
let sigmaOmega = let sigmaOmega =
self.runEuclideanAlgorithm(self.field.buildMonomial(twoS, 1), Box::new(syndrome), twoS); self.runEuclideanAlgorithm(self.field.buildMonomial(twoS, 1), Box::new(syndrome), twoS);
@@ -615,9 +656,11 @@ impl ReedSolomonDecoder{
let errorMagnitudes = self.findErrorMagnitudes(&omega, &errorLocations); let errorMagnitudes = self.findErrorMagnitudes(&omega, &errorLocations);
for i in 0..errorLocations.len() { for i in 0..errorLocations.len() {
//for (int i = 0; i < errorLocations.length; i++) { //for (int i = 0; i < errorLocations.length; i++) {
let position = received.len() - 1 - match self.field.log(errorLocations[i]) { let position = received.len()
- 1
- match self.field.log(errorLocations[i]) {
Ok(size) => size, Ok(size) => size,
Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")) Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")),
}; };
if (position < 0) { if (position < 0) {
return Err(ReedSolomonException::new("Bad error location")); return Err(ReedSolomonException::new("Bad error location"));
@@ -627,8 +670,12 @@ impl ReedSolomonDecoder{
Ok(()) Ok(())
} }
fn runEuclideanAlgorithm(&self, a: Box<GenericGFPoly>, b:Box<GenericGFPoly>, R:usize) fn runEuclideanAlgorithm(
-> Result<Vec<GenericGFPoly>, ReedSolomonException> { &self,
a: Box<GenericGFPoly>,
b: Box<GenericGFPoly>,
R: usize,
) -> Result<Vec<GenericGFPoly>, ReedSolomonException> {
// Assume a's degree is >= b's // Assume a's degree is >= b's
if (a.getDegree() < b.getDegree()) { if (a.getDegree() < b.getDegree()) {
let temp = a; let temp = a;
@@ -662,31 +709,37 @@ impl ReedSolomonDecoder{
}; };
while (r.getDegree() >= rLast.getDegree() && !r.isZero()) { while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
let degreeDiff = r.getDegree() - rLast.getDegree(); let degreeDiff = r.getDegree() - rLast.getDegree();
let scale = self.field.multiply(r.getCoefficient(r.getDegree()), dltInverse); let scale = self
.field
.multiply(r.getCoefficient(r.getDegree()), dltInverse);
q = match q.addOrSubtract(self.field.buildMonomial(degreeDiff, scale)) { q = match q.addOrSubtract(self.field.buildMonomial(degreeDiff, scale)) {
Ok(res) => res, Ok(res) => res,
Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")), Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")),
}; };
r = match r.addOrSubtract(match rLast.multiplyByMonomial(degreeDiff, scale) r = match r.addOrSubtract(match rLast.multiplyByMonomial(degreeDiff, scale) {
{
Ok(res) => res, Ok(res) => res,
Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")), Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")),
}) { }) {
Ok(res) => res, Ok(res) => res,
Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")) Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")),
}; };
} }
t = match (match q.multiply(&tLast) { t = match (match q.multiply(&tLast) {
Ok(res) => res, Ok(res) => res,
Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")), Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")),
}).addOrSubtract(tLastLast){ })
.addOrSubtract(tLastLast)
{
Ok(res) => res, Ok(res) => res,
Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")), Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")),
}; };
if (r.getDegree() >= rLast.getDegree()) { if (r.getDegree() >= rLast.getDegree()) {
return Err( ReedSolomonException::new(&format!("Division algorithm failed to reduce polynomial? r: {}, rLast: {}" ,r, rLast))); return Err(ReedSolomonException::new(&format!(
"Division algorithm failed to reduce polynomial? r: {}, rLast: {}",
r, rLast
)));
} }
} }
@@ -704,10 +757,14 @@ Err(err) => return Err(ReedSolomonException::new("ArithmetricException")),
return Ok(vec![*sigma, *omega]); return Ok(vec![*sigma, *omega]);
} }
fn findErrorLocations(&self, errorLocator:&GenericGFPoly) -> Result<Vec<usize>, ReedSolomonException> { fn findErrorLocations(
&self,
errorLocator: &GenericGFPoly,
) -> Result<Vec<usize>, ReedSolomonException> {
// This is a direct application of Chien's search // This is a direct application of Chien's search
let numErrors = errorLocator.getDegree(); let numErrors = errorLocator.getDegree();
if (numErrors == 1) { // shortcut if (numErrors == 1) {
// shortcut
return Ok(vec![errorLocator.getCoefficient(1)]); return Ok(vec![errorLocator.getCoefficient(1)]);
} }
@@ -715,7 +772,9 @@ Err(err) => return Err(ReedSolomonException::new("ArithmetricException")),
let mut e = 0; let mut e = 0;
for i in 1..self.field.getSize() { for i in 1..self.field.getSize() {
//for (int i = 1; i < field.getSize() && e < numErrors; i++) { //for (int i = 1; i < field.getSize() && e < numErrors; i++) {
if e < numErrors { break; } if e < numErrors {
break;
}
if (errorLocator.evaluateAt(i) == 0) { if (errorLocator.evaluateAt(i) == 0) {
result[e] = match self.field.inverse(i) { result[e] = match self.field.inverse(i) {
Ok(res) => res, Ok(res) => res,
@@ -725,12 +784,18 @@ Err(err) => return Err(ReedSolomonException::new("ArithmetricException")),
} }
} }
if (e != numErrors) { if (e != numErrors) {
return Err( ReedSolomonException::new("Error locator degree does not match number of roots")); return Err(ReedSolomonException::new(
"Error locator degree does not match number of roots",
));
} }
return Ok(result); return Ok(result);
} }
fn findErrorMagnitudes( &self,errorEvaluator:&GenericGFPoly, errorLocations:&Vec<usize>) -> Vec<usize> { fn findErrorMagnitudes(
&self,
errorEvaluator: &GenericGFPoly,
errorLocations: &Vec<usize>,
) -> Vec<usize> {
// This is directly applying Forney's Formula // This is directly applying Forney's Formula
let s = errorLocations.len(); let s = errorLocations.len();
let result = Vec::with_capacity(s); let result = Vec::with_capacity(s);
@@ -746,22 +811,26 @@ Err(err) => return Err(ReedSolomonException::new("ArithmetricException")),
// Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug. // 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 // Below is a funny-looking workaround from Steven Parkes
let term = self.field.multiply(errorLocations[j], xiInverse.unwrap()); let term = self.field.multiply(errorLocations[j], xiInverse.unwrap());
let termPlus1 = if (term & 0x1) == 0 { term | 1} else { term & !1}; let termPlus1 = if (term & 0x1) == 0 {
term | 1
} else {
term & !1
};
denominator = self.field.multiply(denominator, termPlus1); denominator = self.field.multiply(denominator, termPlus1);
} }
} }
result[i] = self.field.multiply(errorEvaluator.evaluateAt(xiInverse.unwrap()), result[i] = self.field.multiply(
self.field.inverse(denominator).unwrap()); errorEvaluator.evaluateAt(xiInverse.unwrap()),
self.field.inverse(denominator).unwrap(),
);
if (self.field.getGeneratorBase() != 0) { if (self.field.getGeneratorBase() != 0) {
result[i] = self.field.multiply(result[i], xiInverse.unwrap()); result[i] = self.field.multiply(result[i], xiInverse.unwrap());
} }
} }
return result; return result;
} }
} }
/* /*
* Copyright 2008 ZXing authors * Copyright 2008 ZXing authors
* *
@@ -790,10 +859,8 @@ Err(err) => return Err(ReedSolomonException::new("ArithmetricException")),
* @author William Rucklidge * @author William Rucklidge
*/ */
pub struct ReedSolomonEncoder { pub struct ReedSolomonEncoder {
field: Box<GenericGF>, field: Box<GenericGF>,
cachedGenerators: Vec<GenericGFPoly>, cachedGenerators: Vec<GenericGFPoly>,
} }
impl ReedSolomonEncoder { impl ReedSolomonEncoder {
@@ -806,11 +873,21 @@ impl ReedSolomonEncoder{
fn buildGenerator(&self, degree: usize) -> GenericGFPoly { fn buildGenerator(&self, degree: usize) -> GenericGFPoly {
if degree >= self.cachedGenerators.len() { if degree >= self.cachedGenerators.len() {
let mut lastGenerator = self.cachedGenerators.get(self.cachedGenerators.len() - 1).unwrap(); let mut lastGenerator = self
.cachedGenerators
.get(self.cachedGenerators.len() - 1)
.unwrap();
for d in self.cachedGenerators.len()..=degree { for d in self.cachedGenerators.len()..=degree {
//for (int d = cachedGenerators.size(); d <= degree; d++) { //for (int d = cachedGenerators.size(); d <= degree; d++) {
let nextGenerator = *lastGenerator.multiply( let nextGenerator = *lastGenerator
&GenericGFPoly::new(self.field, &vec![ 1, self.field.exp(d - 1 + self.field.getGeneratorBase()) ]).unwrap()).unwrap(); .multiply(
&GenericGFPoly::new(
self.field,
&vec![1, self.field.exp(d - 1 + self.field.getGeneratorBase())],
)
.unwrap(),
)
.unwrap();
self.cachedGenerators.push(nextGenerator); self.cachedGenerators.push(nextGenerator);
lastGenerator = &nextGenerator; lastGenerator = &nextGenerator;
} }
@@ -818,7 +895,11 @@ impl ReedSolomonEncoder{
return *self.cachedGenerators.get(degree).unwrap(); return *self.cachedGenerators.get(degree).unwrap();
} }
pub fn encode(&self,toEncode:&mut Vec<usize>, ecBytes:usize) -> Result<(),IllegalArgumentException>{ pub fn encode(
&self,
toEncode: &mut Vec<usize>,
ecBytes: usize,
) -> Result<(), IllegalArgumentException> {
if (ecBytes == 0) { if (ecBytes == 0) {
return Err(IllegalArgumentException::new("No error correction bytes")); return Err(IllegalArgumentException::new("No error correction bytes"));
} }
@@ -839,9 +920,9 @@ impl ReedSolomonEncoder{
//for (int i = 0; i < numZeroCoefficients; i++) { //for (int i = 0; i < numZeroCoefficients; i++) {
toEncode[dataBytes + i] = 0; toEncode[dataBytes + i] = 0;
} }
toEncode[dataBytes + numZeroCoefficients..coefficients.len()].clone_from_slice(&coefficients[0..coefficients.len()]); toEncode[dataBytes + numZeroCoefficients..coefficients.len()]
.clone_from_slice(&coefficients[0..coefficients.len()]);
//System.arraycopy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.length); //System.arraycopy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.length);
Ok(()) Ok(())
} }
} }