pdf417 ec + test

This commit is contained in:
Henry Schimke
2022-12-19 12:01:11 -06:00
parent 5b616fe710
commit 75026d6936
14 changed files with 870 additions and 695 deletions

View File

@@ -340,7 +340,12 @@ fn test_aztec() {
test_encode_decode_random(azd12, 3072, 1023);
}
fn corrupt(received: &mut Vec<i32>, howMany: i32, random: &mut rand::rngs::ThreadRng, max: i32) {
pub(crate) fn corrupt(
received: &mut Vec<i32>,
howMany: i32,
random: &mut rand::rngs::ThreadRng,
max: i32,
) {
let mut corrupted = vec![false; received.len()];
//BitSet corrupted = new BitSet(received.length);
let mut j = 0isize;

View File

@@ -1,7 +1,7 @@
#[cfg(test)]
mod GenericGFPolyTestCase;
#[cfg(test)]
mod ReedSolomonTestCase;
pub(crate) mod ReedSolomonTestCase;
/*
* Copyright 2007 ZXing authors
@@ -26,12 +26,13 @@ pub type GenericGFRef = &'static GenericGF;
use lazy_static::lazy_static;
lazy_static! {
static ref AZTEC_DATA_12: GenericGF = GenericGF::new(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1
static ref AZTEC_DATA_12: GenericGF = GenericGF::new(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1
static ref AZTEC_DATA_10: GenericGF = GenericGF::new(0x409, 1024, 1); // x^10 + x^3 + 1
static ref AZTEC_DATA_6: GenericGF = GenericGF::new(0x43, 64, 1); // x^6 + x + 1
static ref AZTEC_PARAM: GenericGF = GenericGF::new(0x13, 16, 1); // x^4 + x + 1
static ref QR_CODE_FIELD_256: GenericGF = GenericGF::new(0x011D, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1
static ref DATA_MATRIX_FIELD_256: GenericGF = GenericGF::new(0x012D, 256, 1); // x^8 + x^5 + x^3 + x^2 + 1
// static ref PDF_417_FIELD: GenericGF = GenericGF::new(3,crate::pdf417::pdf_417_common::NUMBER_OF_CODEWORDS as usize,1);
}
// pub const AZTEC_DATA_12: GenericGF = GenericGF::new(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1
@@ -52,6 +53,7 @@ pub enum PredefinedGenericGF {
DataMatrixField256,
AztecData8,
MaxicodeField64,
// PDF417,
}
/// Replacement for old const options, has the downside of generating new versions whenever one is requested.
@@ -65,6 +67,7 @@ pub fn get_predefined_genericgf(request: PredefinedGenericGF) -> GenericGFRef {
PredefinedGenericGF::DataMatrixField256 | PredefinedGenericGF::AztecData8 => {
&DATA_MATRIX_FIELD_256
} // x^8 + x^5 + x^3 + x^2 + 1
// PredefinedGenericGF::PDF417 => &PDF_417_FIELD,
}
}

View File

@@ -60,7 +60,7 @@ impl ReedSolomonDecoder {
* @param twoS number of error-correction codewords available
* @throws ReedSolomonException if decoding fails for any reason
*/
pub fn decode(&self, received: &mut Vec<i32>, twoS: i32) -> Result<(), Exceptions> {
pub fn decode(&self, received: &mut Vec<i32>, twoS: i32) -> Result<usize, Exceptions> {
let poly = GenericGFPoly::new(self.field, received).unwrap();
let mut syndromeCoefficients = vec![0; twoS as usize];
let mut noError = true;
@@ -74,7 +74,7 @@ impl ReedSolomonDecoder {
}
}
if noError {
return Ok(());
return Ok(0);
}
let syndrome = match GenericGFPoly::new(self.field, &syndromeCoefficients) {
Ok(res) => res,
@@ -97,7 +97,7 @@ impl ReedSolomonDecoder {
//for (int i = 0; i < errorLocations.length; i++) {
let log_value = self.field.log(errorLocations[i] as i32)?;
if log_value > received.len() as i32 - 1 {
return Ok(());
return Ok(0);
}
let position: isize = received.len() as isize - 1 - log_value as isize;
if position < 0 {
@@ -108,7 +108,7 @@ impl ReedSolomonDecoder {
received[position as usize] =
GenericGF::addOrSubtract(received[position as usize], errorMagnitudes[i]);
}
Ok(())
Ok(errorLocations.len())
}
fn runEuclideanAlgorithm(

View File

@@ -1,55 +0,0 @@
/*
* Copyright 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.pdf417.decoder.ec;
import com.google.zxing.common.reedsolomon.ReedSolomonTestCase;
import org.junit.Assert;
import java.util.BitSet;
import java.util.Random;
/**
* @author Sean Owen
*/
abstract class AbstractErrorCorrectionTestCase extends Assert {
static void corrupt(int[] received, int howMany, Random random) {
ReedSolomonTestCase.corrupt(received, howMany, random, 929);
}
static int[] erase(int[] received, int howMany, Random random) {
BitSet erased = new BitSet(received.length);
int[] erasures = new int[howMany];
int erasureOffset = 0;
for (int j = 0; j < howMany; j++) {
int location = random.nextInt(received.length);
if (erased.get(location)) {
j--;
} else {
erased.set(location);
received[location] = 0;
erasures[erasureOffset++] = location;
}
}
return erasures;
}
static Random getRandom() {
return new Random(0xDEADBEEF);
}
}

View File

@@ -1,190 +0,0 @@
/*
* Copyright 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.pdf417.decoder.ec;
import com.google.zxing.ChecksumException;
/**
* <p>PDF417 error correction implementation.</p>
*
* <p>This <a href="http://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction#Example">example</a>
* is quite useful in understanding the algorithm.</p>
*
* @author Sean Owen
* @see com.google.zxing.common.reedsolomon.ReedSolomonDecoder
*/
public final class ErrorCorrection {
private final ModulusGF field;
public ErrorCorrection() {
this.field = ModulusGF.PDF417_GF;
}
/**
* @param received received codewords
* @param numECCodewords number of those codewords used for EC
* @param erasures location of erasures
* @return number of errors
* @throws ChecksumException if errors cannot be corrected, maybe because of too many errors
*/
public int decode(int[] received,
int numECCodewords,
int[] erasures) throws ChecksumException {
ModulusPoly poly = new ModulusPoly(field, received);
int[] S = new int[numECCodewords];
boolean error = false;
for (int i = numECCodewords; i > 0; i--) {
int eval = poly.evaluateAt(field.exp(i));
S[numECCodewords - i] = eval;
if (eval != 0) {
error = true;
}
}
if (!error) {
return 0;
}
ModulusPoly knownErrors = field.getOne();
if (erasures != null) {
for (int erasure : erasures) {
int b = field.exp(received.length - 1 - erasure);
// Add (1 - bx) term:
ModulusPoly term = new ModulusPoly(field, new int[]{field.subtract(0, b), 1});
knownErrors = knownErrors.multiply(term);
}
}
ModulusPoly syndrome = new ModulusPoly(field, S);
//syndrome = syndrome.multiply(knownErrors);
ModulusPoly[] sigmaOmega =
runEuclideanAlgorithm(field.buildMonomial(numECCodewords, 1), syndrome, numECCodewords);
ModulusPoly sigma = sigmaOmega[0];
ModulusPoly omega = sigmaOmega[1];
//sigma = sigma.multiply(knownErrors);
int[] errorLocations = findErrorLocations(sigma);
int[] errorMagnitudes = findErrorMagnitudes(omega, sigma, errorLocations);
for (int i = 0; i < errorLocations.length; i++) {
int position = received.length - 1 - field.log(errorLocations[i]);
if (position < 0) {
throw ChecksumException.getChecksumInstance();
}
received[position] = field.subtract(received[position], errorMagnitudes[i]);
}
return errorLocations.length;
}
private ModulusPoly[] runEuclideanAlgorithm(ModulusPoly a, ModulusPoly b, int R)
throws ChecksumException {
// Assume a's degree is >= b's
if (a.getDegree() < b.getDegree()) {
ModulusPoly temp = a;
a = b;
b = temp;
}
ModulusPoly rLast = a;
ModulusPoly r = b;
ModulusPoly tLast = field.getZero();
ModulusPoly t = field.getOne();
// Run Euclidean algorithm until r's degree is less than R/2
while (r.getDegree() >= R / 2) {
ModulusPoly rLastLast = rLast;
ModulusPoly 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 ChecksumException.getChecksumInstance();
}
r = rLastLast;
ModulusPoly q = field.getZero();
int denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree());
int dltInverse = field.inverse(denominatorLeadingTerm);
while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
int degreeDiff = r.getDegree() - rLast.getDegree();
int scale = field.multiply(r.getCoefficient(r.getDegree()), dltInverse);
q = q.add(field.buildMonomial(degreeDiff, scale));
r = r.subtract(rLast.multiplyByMonomial(degreeDiff, scale));
}
t = q.multiply(tLast).subtract(tLastLast).negative();
}
int sigmaTildeAtZero = t.getCoefficient(0);
if (sigmaTildeAtZero == 0) {
throw ChecksumException.getChecksumInstance();
}
int inverse = field.inverse(sigmaTildeAtZero);
ModulusPoly sigma = t.multiply(inverse);
ModulusPoly omega = r.multiply(inverse);
return new ModulusPoly[]{sigma, omega};
}
private int[] findErrorLocations(ModulusPoly errorLocator) throws ChecksumException {
// This is a direct application of Chien's search
int numErrors = errorLocator.getDegree();
int[] result = new int[numErrors];
int e = 0;
for (int i = 1; i < field.getSize() && e < numErrors; i++) {
if (errorLocator.evaluateAt(i) == 0) {
result[e] = field.inverse(i);
e++;
}
}
if (e != numErrors) {
throw ChecksumException.getChecksumInstance();
}
return result;
}
private int[] findErrorMagnitudes(ModulusPoly errorEvaluator,
ModulusPoly errorLocator,
int[] errorLocations) {
int errorLocatorDegree = errorLocator.getDegree();
if (errorLocatorDegree < 1) {
return new int[0];
}
int[] formalDerivativeCoefficients = new int[errorLocatorDegree];
for (int i = 1; i <= errorLocatorDegree; i++) {
formalDerivativeCoefficients[errorLocatorDegree - i] =
field.multiply(i, errorLocator.getCoefficient(i));
}
ModulusPoly formalDerivative = new ModulusPoly(field, formalDerivativeCoefficients);
// 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 numerator = field.subtract(0, errorEvaluator.evaluateAt(xiInverse));
int denominator = field.inverse(formalDerivative.evaluateAt(xiInverse));
result[i] = field.multiply(numerator, denominator);
}
return result;
}
}

View File

@@ -1,98 +0,0 @@
/*
* Copyright 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.pdf417.decoder.ec;
import com.google.zxing.ChecksumException;
import org.junit.Test;
import java.util.Random;
/**
* @author Sean Owen
*/
public final class ErrorCorrectionTestCase extends AbstractErrorCorrectionTestCase {
private static final int[] PDF417_TEST = {
48, 901, 56, 141, 627, 856, 330, 69, 244, 900, 852, 169, 843, 895, 852, 895, 913, 154, 845, 778, 387, 89, 869,
901, 219, 474, 543, 650, 169, 201, 9, 160, 35, 70, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
900, 900};
private static final int[] PDF417_TEST_WITH_EC = {
48, 901, 56, 141, 627, 856, 330, 69, 244, 900, 852, 169, 843, 895, 852, 895, 913, 154, 845, 778, 387, 89, 869,
901, 219, 474, 543, 650, 169, 201, 9, 160, 35, 70, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
900, 900, 769, 843, 591, 910, 605, 206, 706, 917, 371, 469, 79, 718, 47, 777, 249, 262, 193, 620, 597, 477, 450,
806, 908, 309, 153, 871, 686, 838, 185, 674, 68, 679, 691, 794, 497, 479, 234, 250, 496, 43, 347, 582, 882, 536,
322, 317, 273, 194, 917, 237, 420, 859, 340, 115, 222, 808, 866, 836, 417, 121, 833, 459, 64, 159};
private static final int ECC_BYTES = PDF417_TEST_WITH_EC.length - PDF417_TEST.length;
private static final int ERROR_LIMIT = ECC_BYTES;
private static final int MAX_ERRORS = ERROR_LIMIT / 2;
private static final int MAX_ERASURES = ERROR_LIMIT;
private final ErrorCorrection ec = new ErrorCorrection();
@Test
public void testNoError() throws ChecksumException {
int[] received = PDF417_TEST_WITH_EC.clone();
// no errors
checkDecode(received);
}
@Test
public void testOneError() throws ChecksumException {
Random random = getRandom();
for (int i = 0; i < PDF417_TEST_WITH_EC.length; i++) {
int[] received = PDF417_TEST_WITH_EC.clone();
received[i] = random.nextInt(256);
checkDecode(received);
}
}
@Test
public void testMaxErrors() throws ChecksumException {
Random random = getRandom();
for (int testIterations = 0; testIterations < 100; testIterations++) { // # iterations is kind of arbitrary
int[] received = PDF417_TEST_WITH_EC.clone();
corrupt(received, MAX_ERRORS, random);
checkDecode(received);
}
}
@Test
public void testTooManyErrors() {
int[] received = PDF417_TEST_WITH_EC.clone();
Random random = getRandom();
corrupt(received, MAX_ERRORS + 1, random);
try {
checkDecode(received);
fail("Should not have decoded");
} catch (ChecksumException ce) {
// good
}
}
private void checkDecode(int[] received) throws ChecksumException {
checkDecode(received, new int[0]);
}
private void checkDecode(int[] received, int[] erasures) throws ChecksumException {
ec.decode(received, ECC_BYTES, erasures);
for (int i = 0; i < PDF417_TEST.length; i++) {
assertEquals(received[i], PDF417_TEST[i]);
}
}
}

View File

@@ -1,112 +0,0 @@
/*
* Copyright 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.pdf417.decoder.ec;
import com.google.zxing.pdf417.PDF417Common;
/**
* <p>A field based on powers of a generator integer, modulo some modulus.</p>
*
* @author Sean Owen
* @see com.google.zxing.common.reedsolomon.GenericGF
*/
public final class ModulusGF {
public static final ModulusGF PDF417_GF = new ModulusGF(PDF417Common.NUMBER_OF_CODEWORDS, 3);
private final int[] expTable;
private final int[] logTable;
private final ModulusPoly zero;
private final ModulusPoly one;
private final int modulus;
private ModulusGF(int modulus, int generator) {
this.modulus = modulus;
expTable = new int[modulus];
logTable = new int[modulus];
int x = 1;
for (int i = 0; i < modulus; i++) {
expTable[i] = x;
x = (x * generator) % modulus;
}
for (int i = 0; i < modulus - 1; i++) {
logTable[expTable[i]] = i;
}
// logTable[0] == 0 but this should never be used
zero = new ModulusPoly(this, new int[]{0});
one = new ModulusPoly(this, new int[]{1});
}
ModulusPoly getZero() {
return zero;
}
ModulusPoly getOne() {
return one;
}
ModulusPoly buildMonomial(int degree, int coefficient) {
if (degree < 0) {
throw new IllegalArgumentException();
}
if (coefficient == 0) {
return zero;
}
int[] coefficients = new int[degree + 1];
coefficients[0] = coefficient;
return new ModulusPoly(this, coefficients);
}
int add(int a, int b) {
return (a + b) % modulus;
}
int subtract(int a, int b) {
return (modulus + a - b) % modulus;
}
int exp(int a) {
return expTable[a];
}
int log(int a) {
if (a == 0) {
throw new IllegalArgumentException();
}
return logTable[a];
}
int inverse(int a) {
if (a == 0) {
throw new ArithmeticException();
}
return expTable[modulus - logTable[a] - 1];
}
int multiply(int a, int b) {
if (a == 0 || b == 0) {
return 0;
}
return expTable[(logTable[a] + logTable[b]) % (modulus - 1)];
}
int getSize() {
return modulus;
}
}

View File

@@ -1,233 +0,0 @@
/*
* Copyright 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.pdf417.decoder.ec;
/**
* @author Sean Owen
*/
final class ModulusPoly {
private final ModulusGF field;
private final int[] coefficients;
ModulusPoly(ModulusGF field, int[] coefficients) {
if (coefficients.length == 0) {
throw new IllegalArgumentException();
}
this.field = field;
int coefficientsLength = coefficients.length;
if (coefficientsLength > 1 && coefficients[0] == 0) {
// Leading term must be non-zero for anything except the constant polynomial "0"
int firstNonZero = 1;
while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) {
firstNonZero++;
}
if (firstNonZero == coefficientsLength) {
this.coefficients = new int[]{0};
} else {
this.coefficients = new int[coefficientsLength - firstNonZero];
System.arraycopy(coefficients,
firstNonZero,
this.coefficients,
0,
this.coefficients.length);
}
} else {
this.coefficients = coefficients;
}
}
int[] getCoefficients() {
return coefficients;
}
/**
* @return degree of this polynomial
*/
int getDegree() {
return coefficients.length - 1;
}
/**
* @return true iff this polynomial is the monomial "0"
*/
boolean isZero() {
return coefficients[0] == 0;
}
/**
* @return coefficient of x^degree term in this polynomial
*/
int getCoefficient(int degree) {
return coefficients[coefficients.length - 1 - degree];
}
/**
* @return evaluation of this polynomial at a given point
*/
int evaluateAt(int a) {
if (a == 0) {
// Just return the x^0 coefficient
return getCoefficient(0);
}
if (a == 1) {
// Just the sum of the coefficients
int result = 0;
for (int coefficient : coefficients) {
result = field.add(result, coefficient);
}
return result;
}
int result = coefficients[0];
int size = coefficients.length;
for (int i = 1; i < size; i++) {
result = field.add(field.multiply(a, result), coefficients[i]);
}
return result;
}
ModulusPoly add(ModulusPoly other) {
if (!field.equals(other.field)) {
throw new IllegalArgumentException("ModulusPolys do not have same ModulusGF field");
}
if (isZero()) {
return other;
}
if (other.isZero()) {
return this;
}
int[] smallerCoefficients = this.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
System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
for (int i = lengthDiff; i < largerCoefficients.length; i++) {
sumDiff[i] = field.add(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
}
return new ModulusPoly(field, sumDiff);
}
ModulusPoly subtract(ModulusPoly other) {
if (!field.equals(other.field)) {
throw new IllegalArgumentException("ModulusPolys do not have same ModulusGF field");
}
if (other.isZero()) {
return this;
}
return add(other.negative());
}
ModulusPoly multiply(ModulusPoly other) {
if (!field.equals(other.field)) {
throw new IllegalArgumentException("ModulusPolys do not have same ModulusGF field");
}
if (isZero() || other.isZero()) {
return field.getZero();
}
int[] aCoefficients = this.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] = field.add(product[i + j], field.multiply(aCoeff, bCoefficients[j]));
}
}
return new ModulusPoly(field, product);
}
ModulusPoly negative() {
int size = coefficients.length;
int[] negativeCoefficients = new int[size];
for (int i = 0; i < size; i++) {
negativeCoefficients[i] = field.subtract(0, coefficients[i]);
}
return new ModulusPoly(field, negativeCoefficients);
}
ModulusPoly multiply(int scalar) {
if (scalar == 0) {
return field.getZero();
}
if (scalar == 1) {
return this;
}
int size = coefficients.length;
int[] product = new int[size];
for (int i = 0; i < size; i++) {
product[i] = field.multiply(coefficients[i], scalar);
}
return new ModulusPoly(field, product);
}
ModulusPoly multiplyByMonomial(int degree, int coefficient) {
if (degree < 0) {
throw new IllegalArgumentException();
}
if (coefficient == 0) {
return field.getZero();
}
int size = coefficients.length;
int[] product = new int[size + degree];
for (int i = 0; i < size; i++) {
product[i] = field.multiply(coefficients[i], coefficient);
}
return new ModulusPoly(field, product);
}
@Override
public String toString() {
StringBuilder result = new StringBuilder(8 * getDegree());
for (int degree = getDegree(); degree >= 0; degree--) {
int coefficient = getCoefficient(degree);
if (coefficient != 0) {
if (coefficient < 0) {
result.append(" - ");
coefficient = -coefficient;
} else {
if (result.length() > 0) {
result.append(" + ");
}
}
if (degree == 0 || coefficient != 1) {
result.append(coefficient);
}
if (degree != 0) {
if (degree == 1) {
result.append('x');
} else {
result.append("x^");
result.append(degree);
}
}
}
}
return result.toString();
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use rand::Rng;
use crate::common::reedsolomon::ReedSolomonTestCase;
/**
* @author Sean Owen
*/
pub fn corrupt(received: &mut [u32], howMany: u32, random: &mut rand::rngs::ThreadRng) {
let mut pass: Vec<i32> = received.iter().map(|x| *x as i32).collect();
ReedSolomonTestCase::corrupt(&mut pass, howMany as i32, random, 929);
for i in 0..received.len() {
received[i] = pass[i] as u32;
}
}
pub fn erase(received: &mut [u32], howMany: u32, random: &mut rand::rngs::ThreadRng) -> Vec<u32> {
let mut erased = vec![false; received.len()]; //BitSet::new(received.len());
let mut erasures = vec![0_u32; howMany as usize];
let mut erasureOffset = 0;
let mut j = 0;
while j < howMany {
// for (int j = 0; j < howMany; j++) {
let location = random.gen_range(0..received.len()); //random.nextInt(received.len());
if *erased.get(location).unwrap() {
j -= 1;
} else {
erased[location] = true;
received[location] = 0;
erasures[erasureOffset] = location as u32;
erasureOffset += 1;
}
j += 1;
}
erasures
}
pub fn getRandom() -> rand::rngs::ThreadRng {
rand::thread_rng()
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use std::rc::Rc;
use crate::{
pdf417::{decoder::ec::ModulusGF, pdf_417_common::NUMBER_OF_CODEWORDS},
Exceptions,
};
use super::ModulusPoly;
use lazy_static::lazy_static;
lazy_static! {
// static ref PDF417_GF : Rc<&ModulusGF> = Rc::new(&ModulusGF::new(NUMBER_OF_CODEWORDS, 3));
static ref fld_interior : ModulusGF = ModulusGF::new(NUMBER_OF_CODEWORDS, 3);
}
/**
* <p>PDF417 error correction implementation.</p>
*
* <p>This <a href="http://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction#Example">example</a>
* is quite useful in understanding the algorithm.</p>
*
* @author Sean Owen
* @see com.google.zxing.common.reedsolomon.ReedSolomonDecoder
*/
/**
* @param received received codewords
* @param numECCodewords number of those codewords used for EC
* @param erasures location of erasures
* @return number of errors
* @throws ChecksumException if errors cannot be corrected, maybe because of too many errors
*/
pub fn decode<'a>(
received: &mut [u32],
numECCodewords: u32,
erasures: &mut [u32],
) -> Result<usize, Exceptions> {
let field: Rc<&'static ModulusGF> = Rc::new(&fld_interior);
let poly = ModulusPoly::new(field.clone(), received.to_vec())?;
let mut S = vec![0u32; numECCodewords as usize];
let mut error = false;
for i in (1..=numECCodewords).rev() {
// for (int i = numECCodewords; i > 0; i--) {
let eval = poly.evaluateAt(field.exp(i));
S[(numECCodewords - i) as usize] = eval;
if eval != 0 {
error = true;
}
}
if !error {
return Ok(0);
}
let mut knownErrors: Rc<ModulusPoly> = ModulusPoly::getOne(field.clone());
let mut b;
let mut term;
let mut kE: Rc<ModulusPoly>;
if !erasures.is_empty() {
for erasure in erasures {
// for (int erasure : erasures) {
b = field.exp(received.len() as u32 - 1 - *erasure);
// Add (1 - bx) term:
term = ModulusPoly::new(field.clone(), vec![field.subtract(0, b), 1])?;
kE = knownErrors.clone();
knownErrors = kE.multiply(Rc::new(term))?;
}
}
let syndrome = Rc::new(ModulusPoly::new(field.clone(), S)?);
//syndrome = syndrome.multiply(knownErrors);
let sigmaOmega = runEuclideanAlgorithm(
ModulusPoly::buildMonomial(field.clone(), numECCodewords as usize, 1),
syndrome,
numECCodewords,
field.clone(),
)?;
let sigma = sigmaOmega[0].clone();
let omega = sigmaOmega[1].clone();
//sigma = sigma.multiply(knownErrors);
let mut errorLocations = findErrorLocations(sigma.clone(), field.clone())?;
let errorMagnitudes = findErrorMagnitudes(omega, sigma, &mut errorLocations, field.clone());
for i in 0..errorLocations.len() {
// for (int i = 0; i < errorLocations.length; i++) {
let position = received.len() as isize - 1 - field.log(errorLocations[i])? as isize;
if position < 0 {
return Err(Exceptions::ChecksumException(format!("{}", file!())));
}
received[position as usize] =
field.subtract(received[position as usize], errorMagnitudes[i]);
}
Ok(errorLocations.len())
}
fn runEuclideanAlgorithm(
a: Rc<ModulusPoly>,
b: Rc<ModulusPoly>,
R: u32,
field: Rc<&'static ModulusGF>,
) -> Result<[Rc<ModulusPoly>; 2], Exceptions> {
// Assume a's degree is >= b's
let mut a = a;
let mut b = b;
if a.getDegree() < b.getDegree() {
let temp = a;
a = b;
b = temp;
}
let mut rLast = a;
let mut r = b;
let mut tLast = ModulusPoly::getZero(field.clone());
let mut t = ModulusPoly::getOne(field.clone());
// Run Euclidean algorithm until r's degree is less than R/2
while r.getDegree() >= R / 2 {
let rLastLast = rLast.clone();
let tLastLast = tLast.clone();
rLast = r;
tLast = t;
// Divide rLastLast by rLast, with quotient in q and remainder in r
if rLast.isZero() {
// Oops, Euclidean algorithm already terminated?
return Err(Exceptions::ChecksumException(format!("{}", file!())));
}
r = rLastLast;
let mut q = ModulusPoly::getZero(field.clone()); //field.getZero();
let denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree() as usize);
let dltInverse = field.inverse(denominatorLeadingTerm)?;
while r.getDegree() >= rLast.getDegree() && !r.isZero() {
let degreeDiff = r.getDegree() - rLast.getDegree();
let scale = field.multiply(r.getCoefficient(r.getDegree() as usize), dltInverse);
q = q.add(ModulusPoly::buildMonomial(
field.clone(),
degreeDiff as usize,
scale,
))?;
r = r.subtract(rLast.multiplyByMonomial(degreeDiff as usize, scale))?;
}
t = q.multiply(tLast.clone())?.subtract(tLastLast)?.negative();
}
let sigmaTildeAtZero = t.getCoefficient(0);
if sigmaTildeAtZero == 0 {
return Err(Exceptions::ChecksumException(format!("{}", file!())));
}
let inverse = field.inverse(sigmaTildeAtZero)?;
let sigma = t.multiplyByScaler(inverse);
let omega = r.multiplyByScaler(inverse);
Ok([sigma, omega])
}
fn findErrorLocations(
errorLocator: Rc<ModulusPoly>,
field: Rc<&ModulusGF>,
) -> Result<Vec<u32>, Exceptions> {
// This is a direct application of Chien's search
let numErrors = errorLocator.getDegree();
let mut result = vec![0u32; numErrors as usize];
let mut e = 0;
let mut i = 1;
while i < field.getSize() && e < numErrors {
// for (int i = 1; i < PDF417_GF.getSize() && e < numErrors; i++) {
if errorLocator.evaluateAt(i) == 0 {
result[e as usize] = field.inverse(i)?;
e += 1;
}
i += 1;
}
if e != numErrors {
return Err(Exceptions::ChecksumException(format!("{}", file!())));
}
Ok(result)
}
fn findErrorMagnitudes(
errorEvaluator: Rc<ModulusPoly>,
errorLocator: Rc<ModulusPoly>,
errorLocations: &mut [u32],
field: Rc<&'static ModulusGF>,
) -> Vec<u32> {
let errorLocatorDegree = errorLocator.getDegree();
if errorLocatorDegree < 1 {
return vec![0; 0];
}
let mut formalDerivativeCoefficients = vec![0u32; errorLocatorDegree as usize];
for i in 1..=errorLocatorDegree {
// for (int i = 1; i <= errorLocatorDegree; i++) {
formalDerivativeCoefficients[errorLocatorDegree as usize - i as usize] =
field.multiply(i, errorLocator.getCoefficient(i as usize));
}
let formalDerivative = ModulusPoly::new(field.clone(), formalDerivativeCoefficients)
.expect("should generate good poly");
// This is directly applying Forney's Formula
let s = errorLocations.len();
let mut result = vec![0u32; s];
for i in 0..s {
// for (int i = 0; i < s; i++) {
let xiInverse = field.inverse(errorLocations[i]).expect("must invert");
let numerator = field.subtract(0, errorEvaluator.evaluateAt(xiInverse));
let denominator = field
.inverse(formalDerivative.evaluateAt(xiInverse))
.expect("must invert");
result[i] = field.multiply(numerator, denominator);
}
result
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use rand::Rng;
use crate::{datamatrix::encoder::error_correction, Exceptions};
use super::{
abstract_error_correction_test_case::{corrupt, getRandom},
error_correction::decode,
};
/**
* @author Sean Owen
*/
const PDF417_TEST: [u32; 48] = [
48, 901, 56, 141, 627, 856, 330, 69, 244, 900, 852, 169, 843, 895, 852, 895, 913, 154, 845,
778, 387, 89, 869, 901, 219, 474, 543, 650, 169, 201, 9, 160, 35, 70, 900, 900, 900, 900, 900,
900, 900, 900, 900, 900, 900, 900, 900, 900,
];
const PDF417_TEST_WITH_EC: [u32; 112] = [
48, 901, 56, 141, 627, 856, 330, 69, 244, 900, 852, 169, 843, 895, 852, 895, 913, 154, 845,
778, 387, 89, 869, 901, 219, 474, 543, 650, 169, 201, 9, 160, 35, 70, 900, 900, 900, 900, 900,
900, 900, 900, 900, 900, 900, 900, 900, 900, 769, 843, 591, 910, 605, 206, 706, 917, 371, 469,
79, 718, 47, 777, 249, 262, 193, 620, 597, 477, 450, 806, 908, 309, 153, 871, 686, 838, 185,
674, 68, 679, 691, 794, 497, 479, 234, 250, 496, 43, 347, 582, 882, 536, 322, 317, 273, 194,
917, 237, 420, 859, 340, 115, 222, 808, 866, 836, 417, 121, 833, 459, 64, 159,
];
const ECC_BYTES: usize = PDF417_TEST_WITH_EC.len() - PDF417_TEST.len();
const ERROR_LIMIT: usize = ECC_BYTES;
const MAX_ERRORS: usize = ERROR_LIMIT / 2;
const _MAX_ERASURES: usize = ERROR_LIMIT;
// private final ErrorCorrection ec = new ErrorCorrection();
#[test]
fn testNoError() {
let mut received = PDF417_TEST_WITH_EC.clone();
// no errors
checkDecode(&mut received).expect("ok");
}
#[test]
fn testExplicitError() {
let mut random = getRandom();
for i in 0..PDF417_TEST_WITH_EC.len() {
// for (int i = 0; i < PDF417_TEST_WITH_EC.length; i++) {
let mut received = PDF417_TEST_WITH_EC.clone();
received[i] = 610; //random.gen_range(0..256);// random.nextInt(256);
checkDecode(&mut received).expect("ok");
}
}
#[test]
fn testOneError() {
let mut random = getRandom();
for i in 0..PDF417_TEST_WITH_EC.len() {
// for (int i = 0; i < PDF417_TEST_WITH_EC.length; i++) {
let mut received = PDF417_TEST_WITH_EC.clone();
received[i] = random.gen_range(0..256); //random.gen_range(0..256);// random.nextInt(256);
checkDecode(&mut received).expect("ok");
}
}
#[test]
fn testMaxErrors() {
let mut random = getRandom();
for _testIterations in 0..100 {
// for (int testIterations = 0; testIterations < 100; testIterations++) { // # iterations is kind of arbitrary
let mut received = PDF417_TEST_WITH_EC.clone();
corrupt(&mut received, MAX_ERRORS as u32, &mut random);
checkDecode(&mut received).expect("ok");
}
}
#[test]
fn testTooManyErrors() {
let mut received = PDF417_TEST_WITH_EC.clone();
let mut random = getRandom();
corrupt(&mut received, MAX_ERRORS as u32 + 1, &mut random);
// try {
assert!(checkDecode(&mut received).is_err());
// fail("Should not have decoded");
// } catch (ChecksumException ce) {
// // good
// }
}
fn checkDecode(received: &mut [u32]) -> Result<(), Exceptions> {
checkDecodeErasures(received, &mut [0_u32; 0])
}
fn checkDecodeErasures(received: &mut [u32], erasures: &mut [u32]) -> Result<(), Exceptions> {
decode(received, ECC_BYTES as u32, erasures)?;
// ec.decode(received, ECC_BYTES, erasures);
for i in 0..PDF417_TEST.len() {
// for (int i = 0; i < PDF417_TEST.length; i++) {
assert_eq!(received[i], PDF417_TEST[i]);
}
Ok(())
}

View File

@@ -1 +1,12 @@
mod modulus_gf;
pub use modulus_gf::*;
mod modulus_poly;
pub use modulus_poly::*;
pub mod error_correction;
#[cfg(test)]
mod abstract_error_correction_test_case;
#[cfg(test)]
mod error_correction_test_case;

View File

@@ -0,0 +1,117 @@
/*
* Copyright 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//public static final ModulusGF PDF417_GF = new ModulusGF(PDF417Common.NUMBER_OF_CODEWORDS, 3);
use std::rc::Rc;
use crate::Exceptions;
use super::ModulusPoly;
/**
* <p>A field based on powers of a generator integer, modulo some modulus.</p>
*
* @author Sean Owen
* @see com.google.zxing.common.reedsolomon.GenericGF
*/
#[derive(Debug, Clone)]
pub struct ModulusGF {
expTable: Vec<u32>,
logTable: Vec<u32>,
// zero: Option<Rc<ModulusPoly<'a>>>,
// one: Option<Rc<ModulusPoly<'a>>>,
modulus: u32,
generator: u32,
}
impl ModulusGF {
pub fn new(modulus: u32, generator: u32) -> Self {
let mut expTable = vec![0u32; modulus as usize]; //new int[modulus];
let mut logTable = vec![0u32; modulus as usize]; //new int[modulus];
let mut x = 1;
for i in 0..modulus as usize {
// for (int i = 0; i < modulus; i++) {
expTable[i] = x;
x = (x * generator) % modulus;
}
for i in 0..modulus as usize - 1 {
// for (int i = 0; i < modulus - 1; i++) {
logTable[expTable[i] as usize] = i as u32;
}
// logTable[0] == 0 but this should never be used
let potential_self = Self {
expTable,
logTable,
// zero: None,
// one: None,
modulus,
generator,
};
// zero = new ModulusPoly(this, new int[]{0});
// one = new ModulusPoly(this, new int[]{1});
potential_self
}
pub fn add(&self, a: u32, b: u32) -> u32 {
(a + b) % self.modulus
}
pub fn subtract(&self, a: u32, b: u32) -> u32 {
(self.modulus + a - b) % self.modulus
}
pub fn exp(&self, a: u32) -> u32 {
self.expTable[a as usize]
}
pub fn log(&self, a: u32) -> Result<u32, Exceptions> {
if a == 0 {
Err(Exceptions::ArithmeticException("".to_owned()))
} else {
Ok(self.logTable[a as usize])
}
}
pub fn inverse(&self, a: u32) -> Result<u32, Exceptions> {
if a == 0 {
Err(Exceptions::ArithmeticException("".to_owned()))
} else {
Ok(self.expTable[self.modulus as usize - self.logTable[a as usize] as usize - 1])
}
}
pub fn multiply(&self, a: u32, b: u32) -> u32 {
if a == 0 || b == 0 {
0
} else {
self.expTable[(self.logTable[a as usize] + self.logTable[b as usize]) as usize
% (self.modulus - 1) as usize]
}
}
pub fn getSize(&self) -> u32 {
self.modulus
}
}
impl PartialEq for ModulusGF {
fn eq(&self, other: &Self) -> bool {
self.modulus == other.modulus && self.generator == other.generator
}
}
impl Eq for ModulusGF {}

View File

@@ -0,0 +1,321 @@
/*
* Copyright 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use std::rc::Rc;
use crate::Exceptions;
use super::ModulusGF;
/**
* @author Sean Owen
*/
#[derive(Clone, Debug)]
pub struct ModulusPoly {
field: Rc<&'static ModulusGF>,
coefficients: Vec<u32>,
// zero: Option<Rc<ModulusPoly>>,
// one: Option<Rc<ModulusPoly>>,
}
impl ModulusPoly {
pub fn new(
field: Rc<&'static ModulusGF>,
coefficients: Vec<u32>,
) -> Result<ModulusPoly, Exceptions> {
if coefficients.is_empty() {
return Err(Exceptions::IllegalArgumentException("".to_owned()));
}
let orig_coefs = coefficients.clone();
let mut coefficients = coefficients;
let coefficientsLength = coefficients.len();
if coefficientsLength > 1 && coefficients[0] == 0 {
// Leading term must be non-zero for anything except the constant polynomial "0"
let mut firstNonZero = 1;
while firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0 {
firstNonZero += 1;
}
if firstNonZero == coefficientsLength {
coefficients = vec![0];
} else {
coefficients = vec![0u32; coefficientsLength - firstNonZero];
coefficients[..].copy_from_slice(&&orig_coefs[firstNonZero..]);
// System.arraycopy(coefficients,
// firstNonZero,
// this.coefficients,
// 0,
// this.coefficients.length);
}
} else {
coefficients = coefficients;
}
Ok(ModulusPoly {
field: field.clone(),
coefficients: coefficients,
// zero: Some(Self::getZero(field.clone())),
// one: Some(Self::getOne(field.clone())),
})
}
pub fn getCoefficients(&self) -> &[u32] {
&self.coefficients
}
/**
* @return degree of this polynomial
*/
pub fn getDegree(&self) -> u32 {
self.coefficients.len() as u32 - 1
}
/**
* @return true iff this polynomial is the monomial "0"
*/
pub fn isZero(&self) -> bool {
self.coefficients[0] == 0
}
/**
* @return coefficient of x^degree term in this polynomial
*/
pub fn getCoefficient(&self, degree: usize) -> u32 {
self.coefficients[self.coefficients.len() - 1 - degree]
}
/**
* @return evaluation of this polynomial at a given point
*/
pub fn evaluateAt(&self, a: u32) -> u32 {
if a == 0 {
// Just return the x^0 coefficient
return self.getCoefficient(0);
}
if a == 1 {
// Just the sum of the coefficients
let mut result = 0;
for coefficient in self.coefficients.iter() {
// for (int coefficient : coefficients) {
result = self.field.add(result, *coefficient);
}
return result;
}
let mut result = self.coefficients[0];
let size = self.coefficients.len();
for i in 1..size {
// for (int i = 1; i < size; i++) {
result = self
.field
.add(self.field.multiply(a, result), self.coefficients[i]);
}
return result;
}
pub fn add(&self, other: Rc<ModulusPoly>) -> Result<Rc<ModulusPoly>, Exceptions> {
if self.field != other.field {
return Err(Exceptions::IllegalArgumentException(
"ModulusPolys do not have same ModulusGF field".to_owned(),
));
}
if self.isZero() {
return Ok(other);
}
if other.isZero() {
return Ok(Rc::new(self.clone()));
}
let mut smallerCoefficients = &self.coefficients;
let mut largerCoefficients = &other.coefficients;
if smallerCoefficients.len() > largerCoefficients.len() {
let temp = smallerCoefficients;
smallerCoefficients = largerCoefficients;
largerCoefficients = temp;
}
let mut sumDiff = vec![0032; largerCoefficients.len()];
let lengthDiff = largerCoefficients.len() - smallerCoefficients.len();
// Copy high-order terms only found in higher-degree polynomial's coefficients
sumDiff[..lengthDiff].copy_from_slice(&largerCoefficients[..lengthDiff]);
// System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
for i in lengthDiff..largerCoefficients.len() {
// for (int i = lengthDiff; i < largerCoefficients.length; i++) {
sumDiff[i] = self
.field
.add(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
}
Ok(Rc::new(
ModulusPoly::new(self.field.clone(), sumDiff)
.expect("should always generate with known goods"),
))
}
pub fn subtract(&self, other: Rc<ModulusPoly>) -> Result<Rc<ModulusPoly>, Exceptions> {
if self.field != other.field {
return Err(Exceptions::IllegalArgumentException(
"ModulusPolys do not have same ModulusGF field".to_owned(),
));
}
if other.isZero() {
return Ok(Rc::new(self.clone()));
};
self.add(other.negative().clone())
}
pub fn multiply(&self, other: Rc<ModulusPoly>) -> Result<Rc<ModulusPoly>, Exceptions> {
if !(self.field == other.field) {
return Err(Exceptions::IllegalArgumentException(
"ModulusPolys do not have same ModulusGF field".to_owned(),
));
}
if self.isZero() || other.isZero() {
return Ok(Self::getZero(self.field.clone()).clone());
}
let aCoefficients = &self.coefficients;
let aLength = aCoefficients.len();
let bCoefficients = &other.coefficients;
let bLength = bCoefficients.len();
let mut product = vec![0u32; aLength + bLength - 1];
for i in 0..aLength {
// for (int i = 0; i < aLength; i++) {
let aCoeff = aCoefficients[i];
for j in 0..bLength {
// for (int j = 0; j < bLength; j++) {
product[i + j] = self.field.add(
product[i + j],
self.field.multiply(aCoeff, bCoefficients[j]),
);
}
}
Ok(Rc::new(
ModulusPoly::new(self.field.clone(), product)
.expect("should always generate with known goods"),
))
}
pub fn negative(&self) -> Rc<ModulusPoly> {
let size = self.coefficients.len();
let mut negativeCoefficients = vec![0u32; size];
for i in 0..size {
// for (int i = 0; i < size; i++) {
negativeCoefficients[i] = self.field.subtract(0, self.coefficients[i]);
}
Rc::new(
ModulusPoly::new(self.field.clone(), negativeCoefficients)
.expect("should always generate with known goods"),
)
}
pub fn multiplyByScaler(&self, scalar: u32) -> Rc<ModulusPoly> {
if scalar == 0 {
return Self::getZero(self.field.clone()).clone();
}
if scalar == 1 {
return Rc::new(self.clone());
}
let size = self.coefficients.len();
let mut product = vec![0u32; size];
for i in 0..size {
// for (int i = 0; i < size; i++) {
product[i] = self.field.multiply(self.coefficients[i], scalar);
}
Rc::new(
ModulusPoly::new(self.field.clone(), product)
.expect("should always generate with known goods"),
)
}
pub fn multiplyByMonomial(&self, degree: usize, coefficient: u32) -> Rc<ModulusPoly> {
if coefficient == 0 {
return Self::getZero(self.field.clone()).clone();
}
let size = self.coefficients.len();
let mut product = vec![0u32; size + degree];
for i in 0..size {
// for (int i = 0; i < size; i++) {
product[i] = self.field.multiply(self.coefficients[i], coefficient);
}
Rc::new(
ModulusPoly::new(self.field.clone(), product)
.expect("should always generate with known goods"),
)
}
pub fn getZero(field: Rc<&'static ModulusGF>) -> Rc<ModulusPoly> {
Rc::new(
ModulusPoly::new(field.clone(), vec![0])
.expect("should always generate with known goods"),
)
}
pub fn getOne(field: Rc<&'static ModulusGF>) -> Rc<ModulusPoly> {
Rc::new(
ModulusPoly::new(field.clone(), vec![1])
.expect("should always generate with known goods"),
)
}
pub fn buildMonomial(
field: Rc<&'static ModulusGF>,
degree: usize,
coefficient: u32,
) -> Rc<ModulusPoly> {
// if degree < 0 {
// throw new IllegalArgumentException();
// }
if coefficient == 0 {
return Self::getZero(field);
}
let mut coefficients = vec![0_u32; degree + 1];
coefficients[0] = coefficient;
Rc::new(
ModulusPoly::new(field.clone(), coefficients)
.expect("should always generate with known goods"),
)
}
// @Override
// public String toString() {
// StringBuilder result = new StringBuilder(8 * getDegree());
// for (int degree = getDegree(); degree >= 0; degree--) {
// int coefficient = getCoefficient(degree);
// if (coefficient != 0) {
// if (coefficient < 0) {
// result.append(" - ");
// coefficient = -coefficient;
// } else {
// if (result.length() > 0) {
// result.append(" + ");
// }
// }
// if (degree == 0 || coefficient != 1) {
// result.append(coefficient);
// }
// if (degree != 0) {
// if (degree == 1) {
// result.append('x');
// } else {
// result.append("x^");
// result.append(degree);
// }
// }
// }
// }
// return result.toString();
// }
}