#include "GenericGFPoly.h"
#include "GenericGF.h"
#include "ZXAlgorithms.h"
#include <algorithm>
#include <cassert>
#include <stdexcept>
namespace ZXing {
int
GenericGFPoly::evaluateAt(int a) const
{
if (a == 0) return constant();
if (a == 1) return Reduce(_coefficients, 0, [](auto s, auto c) { return s ^ c; });
return std::accumulate(_coefficients.begin(), _coefficients.end(), 0,
[this, a](auto s, auto c) { return _field->multiply(a, s) ^ c; });
}
GenericGFPoly& GenericGFPoly::addOrSubtract(GenericGFPoly& other)
{
assert(_field == other._field);
if (isZero()) {
swap(*this, other);
return *this;
}
if (other.isZero())
return *this;
auto& smallerCoefs = other._coefficients;
auto& largerCoefs = _coefficients;
if (smallerCoefs.size() > largerCoefs.size())
std::swap(smallerCoefs, largerCoefs);
size_t lengthDiff = largerCoefs.size() - smallerCoefs.size();
for (size_t i = lengthDiff; i < largerCoefs.size(); ++i)
largerCoefs[i] ^= smallerCoefs[i - lengthDiff];
normalize();
return *this;
}
GenericGFPoly&
GenericGFPoly::multiply(const GenericGFPoly& other)
{
assert(_field == other._field);
if (isZero() || other.isZero())
return setMonomial(0);
auto& a = _coefficients;
auto& b = other._coefficients;
_cache.resize(a.size() + b.size() - 1);
std::fill(_cache.begin(), _cache.end(), 0);
for (size_t i = 0; i < a.size(); ++i)
for (size_t j = 0; j < b.size(); ++j)
_cache[i + j] ^= _field->multiply(a[i], b[j]);
_coefficients.swap(_cache);
normalize();
return *this;
}
GenericGFPoly&
GenericGFPoly::multiplyByMonomial(int coefficient, int degree)
{
assert(degree >= 0);
if (coefficient == 0)
return setMonomial(0);
for (int& c : _coefficients)
c = _field->multiply(c, coefficient);
_coefficients.resize(_coefficients.size() + degree, 0);
normalize();
return *this;
}
GenericGFPoly&
GenericGFPoly::divide(const GenericGFPoly& other, GenericGFPoly& quotient)
{
assert(_field == other._field);
if (other.isZero())
throw std::invalid_argument("Divide by 0");
quotient.setField(*_field);
if (degree() < other.degree()) {
quotient.setMonomial(0);
return *this;
}
std::swap(*this, quotient);
auto& divisor = other._coefficients;
auto& result = quotient._coefficients;
auto normalizer = _field->inverse(divisor[0]);
for (int i = 0; i < Size(result) - (Size(divisor) - 1); ++i) {
auto& ci = result[i];
if (ci == 0)
continue;
ci = _field->multiply(ci, normalizer);
for (int j = 1; j < Size(divisor); ++j)
result[i + j] ^= _field->multiply(divisor[j], ci); }
auto firstNonZero = std::find_if(result.end() - other.degree(), result.end(), [](int c){ return c != 0; });
if (firstNonZero == result.end()) {
setMonomial(0);
} else {
_coefficients.resize(result.end() - firstNonZero);
std::copy(firstNonZero, result.end(), _coefficients.begin());
}
result.resize(result.size() - other.degree());
return *this;
}
void GenericGFPoly::normalize()
{
auto firstNonZero = FindIf(_coefficients, [](int c){ return c != 0; });
if (firstNonZero != _coefficients.begin()) {
if (firstNonZero == _coefficients.end()) {
_coefficients.resize(1, 0);
} else {
std::copy(firstNonZero, _coefficients.end(), _coefficients.begin());
_coefficients.resize(_coefficients.end() - firstNonZero);
}
}
}
}