232 lines
8.7 KiB
C++
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;
|
|
}
|