#include "PDFModulusPoly.h"
#include "PDFModulusGF.h"
#include <algorithm>
#include <stdexcept>
namespace ZXing {
namespace Pdf417 {
ModulusPoly::ModulusPoly(const ModulusGF& field, const std::vector<int>& coefficients) :
_field(&field)
{
size_t coefficientsLength = coefficients.size();
if (coefficientsLength > 1 && coefficients[0] == 0) {
size_t firstNonZero = 1;
while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) {
firstNonZero++;
}
if (firstNonZero == coefficientsLength) {
_coefficients.resize(1, 0);
}
else {
_coefficients.resize(coefficientsLength - firstNonZero);
std::copy(coefficients.begin() + firstNonZero, coefficients.end(), _coefficients.begin());
}
}
else {
_coefficients = coefficients;
}
}
int
ModulusPoly::evaluateAt(int a) const
{
if (a == 0) return coefficient(0);
if (a == 1) return Reduce(_coefficients, 0, [this](auto res, auto coef) { return _field->add(res, coef); });
return std::accumulate(_coefficients.begin(), _coefficients.end(), 0,
[this, a](auto res, auto coef) { return _field->add(_field->multiply(a, res), coef); });
}
ModulusPoly
ModulusPoly::add(const ModulusPoly& other) const
{
if (_field != other._field) {
throw std::invalid_argument("ModulusPolys do not have same ModulusGF field");
}
if (isZero()) {
return other;
}
if (other.isZero()) {
return *this;
}
auto smallerCoefficients = &_coefficients;
auto largerCoefficients = &other._coefficients;
if (smallerCoefficients->size() > largerCoefficients->size()) {
std::swap(smallerCoefficients, largerCoefficients);
}
std::vector<int> sumDiff(largerCoefficients->size());
size_t lengthDiff = largerCoefficients->size() - smallerCoefficients->size();
std::copy_n(largerCoefficients->begin(), lengthDiff, sumDiff.begin());
for (size_t i = lengthDiff; i < largerCoefficients->size(); i++) {
sumDiff[i] = _field->add((*smallerCoefficients)[i - lengthDiff], (*largerCoefficients)[i]);
}
return ModulusPoly(*_field, sumDiff);
}
ModulusPoly
ModulusPoly::subtract(const ModulusPoly& other) const
{
if (_field != other._field) {
throw std::invalid_argument("ModulusPolys do not have same ModulusGF field");
}
if (other.isZero()) {
return *this;
}
return add(other.negative());
}
ModulusPoly
ModulusPoly::multiply(const ModulusPoly& other) const
{
if (_field != other._field) {
throw std::invalid_argument("ModulusPolys do not have same ModulusGF field");
}
if (isZero() || other.isZero()) {
return _field->zero();
}
auto& aCoefficients = _coefficients;
size_t aLength = aCoefficients.size();
auto& bCoefficients = other._coefficients;
size_t bLength = bCoefficients.size();
std::vector<int> product(aLength + bLength - 1, 0);
for (size_t i = 0; i < aLength; i++) {
int aCoeff = aCoefficients[i];
for (size_t j = 0; j < bLength; j++) {
product[i + j] = _field->add(product[i + j], _field->multiply(aCoeff, bCoefficients[j]));
}
}
return ModulusPoly(*_field, product);
}
ModulusPoly
ModulusPoly::negative() const
{
size_t size = _coefficients.size();
std::vector<int> negativeCoefficients(size);
for (size_t i = 0; i < size; i++) {
negativeCoefficients[i] = _field->subtract(0, _coefficients[i]);
}
return ModulusPoly(*_field, negativeCoefficients);
}
ModulusPoly
ModulusPoly::multiply(int scalar) const
{
if (scalar == 0) {
return _field->zero();
}
if (scalar == 1) {
return *this;
}
size_t size = _coefficients.size();
std::vector<int> product(size);
for (size_t i = 0; i < size; i++) {
product[i] = _field->multiply(_coefficients[i], scalar);
}
return ModulusPoly(*_field, product);
}
ModulusPoly
ModulusPoly::multiplyByMonomial(int degree, int coefficient) const
{
if (degree < 0) {
throw std::invalid_argument("degree < 0");
}
if (coefficient == 0) {
return _field->zero();
}
size_t size = _coefficients.size();
std::vector<int> product(size + degree, 0);
for (size_t i = 0; i < size; i++) {
product[i] = _field->multiply(_coefficients[i], coefficient);
}
return ModulusPoly(*_field, product);
}
void
ModulusPoly::divide(const ModulusPoly& other, ModulusPoly& quotient, ModulusPoly& remainder) const
{
if (_field != other._field) {
throw std::invalid_argument("ModulusPolys do not have same ModulusGF field");
}
if (other.isZero()) {
throw std::invalid_argument("Divide by 0");
}
quotient = _field->zero();
remainder = *this;
int denominatorLeadingTerm = other.coefficient(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.coefficient(remainder.degree()), inverseDenominatorLeadingTerm);
ModulusPoly term = other.multiplyByMonomial(degreeDifference, scale);
ModulusPoly iterationQuotient = _field->buildMonomial(degreeDifference, scale);
quotient = quotient.add(iterationQuotient);
remainder = remainder.subtract(term);
}
}
} }