Files
opencv_contrib/modules/wechat_qrcode/src/zxing/common/reedsolomon/genericgfpoly.cpp
2022-05-06 02:00:27 +08:00

232 lines
8.7 KiB
C++

// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../../precomp.hpp"
#include "genericgfpoly.hpp"
#include "genericgf.hpp"
using zxing::ArrayRef;
using zxing::ErrorHandler;
using zxing::GenericGFPoly;
using zxing::Ref;
// VC++
using zxing::GenericGF;
GenericGFPoly::GenericGFPoly(GenericGF &field, ArrayRef<int> coefficients,
ErrorHandler &err_handler)
: field_(field) {
if (coefficients->size() == 0) {
err_handler = IllegalArgumentErrorHandler("need coefficients");
return;
}
int coefficientsLength = coefficients->size();
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) {
coefficients_ = field.getZero()->getCoefficients();
} else {
coefficients_ = ArrayRef<int>(new Array<int>(coefficientsLength - firstNonZero));
for (int i = 0; i < (int)coefficients_->size(); i++) {
coefficients_[i] = coefficients[i + firstNonZero];
}
}
} else {
coefficients_ = coefficients;
}
}
ArrayRef<int> GenericGFPoly::getCoefficients() { return coefficients_; }
int GenericGFPoly::getDegree() { return coefficients_->size() - 1; }
bool GenericGFPoly::isZero() { return coefficients_[0] == 0; }
int GenericGFPoly::getCoefficient(int degree) {
return coefficients_[coefficients_->size() - 1 - degree];
}
int GenericGFPoly::evaluateAt(int a) {
if (a == 0) {
// Just return the x^0 coefficient
return getCoefficient(0);
}
int size = coefficients_->size();
if (a == 1) {
// Just the sum of the coefficients
int result = 0;
for (int i = 0; i < size; i++) {
result = GenericGF::addOrSubtract(result, coefficients_[i]);
}
return result;
}
int result = coefficients_[0];
for (int i = 1; i < size; i++) {
result = GenericGF::addOrSubtract(field_.multiply(a, result), coefficients_[i]);
}
return result;
}
Ref<GenericGFPoly> GenericGFPoly::addOrSubtract(Ref<zxing::GenericGFPoly> other,
ErrorHandler &err_handler) {
if (!(&field_ == &other->field_)) {
err_handler =
IllegalArgumentErrorHandler("GenericGFPolys do not have same GenericGF field");
return Ref<GenericGFPoly>();
}
if (isZero()) {
return other;
}
if (other->isZero()) {
return Ref<GenericGFPoly>(this);
}
ArrayRef<int> smallerCoefficients = coefficients_;
ArrayRef<int> largerCoefficients = other->getCoefficients();
if (smallerCoefficients->size() > largerCoefficients->size()) {
ArrayRef<int> temp = smallerCoefficients;
smallerCoefficients = largerCoefficients;
largerCoefficients = temp;
}
ArrayRef<int> sumDiff(new Array<int>(largerCoefficients->size()));
int lengthDiff = largerCoefficients->size() - smallerCoefficients->size();
// Copy high-order terms only found in higher-degree polynomial's
// coefficients
for (int i = 0; i < lengthDiff; i++) {
sumDiff[i] = largerCoefficients[i];
}
for (int i = lengthDiff; i < (int)largerCoefficients->size(); i++) {
sumDiff[i] =
GenericGF::addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
}
// return Ref<GenericGFPoly>(new GenericGFPoly(field_, sumDiff));
Ref<GenericGFPoly> gfpoly(new GenericGFPoly(field_, sumDiff, err_handler));
if (err_handler.ErrCode()) return Ref<GenericGFPoly>();
return gfpoly;
}
Ref<GenericGFPoly> GenericGFPoly::multiply(Ref<zxing::GenericGFPoly> other,
ErrorHandler &err_handler) {
if (!(&field_ == &other->field_)) {
err_handler =
IllegalArgumentErrorHandler("GenericGFPolys do not have same GenericGF field");
return Ref<GenericGFPoly>();
}
if (isZero() || other->isZero()) {
return field_.getZero();
}
ArrayRef<int> aCoefficients = coefficients_;
int aLength = aCoefficients->size();
ArrayRef<int> bCoefficients = other->getCoefficients();
int bLength = bCoefficients->size();
ArrayRef<int> product(new Array<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 Ref<GenericGFPoly>(new GenericGFPoly(field_, product));
Ref<GenericGFPoly> gfpoly(new GenericGFPoly(field_, product, err_handler));
if (err_handler.ErrCode()) return Ref<GenericGFPoly>();
return gfpoly;
}
Ref<GenericGFPoly> GenericGFPoly::multiply(int scalar, ErrorHandler &err_handler) {
if (scalar == 0) {
return field_.getZero();
}
if (scalar == 1) {
return Ref<GenericGFPoly>(this);
}
int size = coefficients_->size();
ArrayRef<int> product(new Array<int>(size));
for (int i = 0; i < size; i++) {
product[i] = field_.multiply(coefficients_[i], scalar);
}
// return Ref<GenericGFPoly>(new GenericGFPoly(field_, product));
Ref<GenericGFPoly> gfpoly(new GenericGFPoly(field_, product, err_handler));
if (err_handler.ErrCode()) return Ref<GenericGFPoly>();
return gfpoly;
}
Ref<GenericGFPoly> GenericGFPoly::multiplyByMonomial(int degree, int coefficient,
ErrorHandler &err_handler) {
if (degree < 0) {
err_handler = IllegalArgumentErrorHandler("degree must not be less then 0");
return Ref<GenericGFPoly>();
}
if (coefficient == 0) {
return field_.getZero();
}
int size = coefficients_->size();
ArrayRef<int> product(new Array<int>(size + degree));
for (int i = 0; i < size; i++) {
product[i] = field_.multiply(coefficients_[i], coefficient);
}
// return Ref<GenericGFPoly>(new GenericGFPoly(field_, product));
Ref<GenericGFPoly> gfpoly(new GenericGFPoly(field_, product, err_handler));
if (err_handler.ErrCode()) return Ref<GenericGFPoly>();
return gfpoly;
}
std::vector<Ref<GenericGFPoly>> GenericGFPoly::divide(Ref<GenericGFPoly> other,
ErrorHandler &err_handler) {
if (!(&field_ == &other->field_)) {
err_handler =
IllegalArgumentErrorHandler("GenericGFPolys do not have same GenericGF field");
return std::vector<Ref<GenericGFPoly>>();
}
if (other->isZero()) {
err_handler = IllegalArgumentErrorHandler("divide by 0");
return std::vector<Ref<GenericGFPoly>>();
}
Ref<GenericGFPoly> quotient = field_.getZero();
Ref<GenericGFPoly> remainder = Ref<GenericGFPoly>(this);
int denominatorLeadingTerm = other->getCoefficient(other->getDegree());
int inverseDenominatorLeadingTerm = field_.inverse(denominatorLeadingTerm, err_handler);
if (err_handler.ErrCode()) return std::vector<Ref<GenericGFPoly>>();
while (remainder->getDegree() >= other->getDegree() && !remainder->isZero()) {
int degreeDifference = remainder->getDegree() - other->getDegree();
int scale = field_.multiply(remainder->getCoefficient(remainder->getDegree()),
inverseDenominatorLeadingTerm);
Ref<GenericGFPoly> term = other->multiplyByMonomial(degreeDifference, scale, err_handler);
if (err_handler.ErrCode()) return std::vector<Ref<GenericGFPoly>>();
Ref<GenericGFPoly> iterationQuotiont =
field_.buildMonomial(degreeDifference, scale, err_handler);
if (err_handler.ErrCode()) return std::vector<Ref<GenericGFPoly>>();
quotient = quotient->addOrSubtract(iterationQuotiont, err_handler);
remainder = remainder->addOrSubtract(term, err_handler);
if (err_handler.ErrCode()) return std::vector<Ref<GenericGFPoly>>();
}
std::vector<Ref<GenericGFPoly>> returnValue(2);
returnValue[0] = quotient;
returnValue[1] = remainder;
return returnValue;
}