A gf2::BitPolynomial is a polynomial over GF2
where each coefficient
The polynomial coefficients are stored as a gf2::BitVector, and every operation is word-oriented and fast.
gf2::BitPolynomial is declared as:
template <Unsigned Word = usize>
class BitPolynomial {
// ...
};The polynomial's coefficients are stored in a gf2::BitVector, and the Word template parameter specifies the underlying unsigned integer type used to back that vector. The default Word is usually the most efficient type for the target platform.
On most modern CPU's, that usize will be a 64-bit unsigned integer.
If your application calls for a vast number of low-degree polynomials, you might consider using std::uint8_t as the Word type to save memory.
Note
You might notice that many of the doctests in the library use 8-bit underlying words.
The reason is we want to exercise the various methods across word boundaries for modest, easily readable bit-polynomials.
The following constructors are available for gf2::BitPolynomial objects:
| Method Name | Description |
|---|---|
gf2::BitPolynomial::BitPolynomial() |
The default constructor creates the zero bit-polynomial |
gf2::BitPolynomial::BitPolynomial(const BitVector<Word>& coeffs) |
Constructs a bit-vector by copying the passed vector of coefficients. |
gf2::BitPolynomial::BitPolynomial(BitVector<Word>&& coeffs) |
Constructs a bit-vector by moving the passed vector of coefficients. |
If c is a gf2::BitVector representing the coefficients of a polynomial, then gf2::BitPolynomial p{c} creates a gf2::BitPolynomial which copies its coefficients from c.
On the other hand, gf2::BitPolynomial p{std::move(c)} creates a gf2::BitPolynomial which moves c into its coefficients, and leaving c in an unspecified state.
Other construction methods are available as static factory methods:
| Method Name | Description |
|---|---|
gf2::BitPolynomial::zero |
Returns the constant zero polynomial |
gf2::BitPolynomial::one |
Returns the constant polynomial |
gf2::BitPolynomial::constant |
Returns the constant polynomial |
gf2::BitPolynomial::zeros |
Returns the polynomial |
gf2::BitPolynomial::ones |
Returns the polynomial |
gf2::BitPolynomial::x_to_the |
Returns the polynomial |
gf2::BitPolynomial::from |
Returns a polynomial whose coefficients are determined by repeatedly calling the passed function. |
gf2::BitPolynomial::random |
Returns a random polynomial of a particular degree. |
gf2::BitPolynomial::seeded_random |
Returns a random polynomial of a particular degree, determined by an RNG seeded for repeatability. |
It is worth noting that there are multiple representations possible for the zero polynomial
In the library, the empty polynomial (the one with no coefficients at all) is considered to be a zero polynomial.
So also is the polynomial gf2::BitPolynomial::zeros(n).
There following methods query a gf2::BitPolynomial object:
| Method Name | Description |
|---|---|
gf2::BitPolynomial::degree |
Returns the degree of the polynomial (returns 0 for any zero polynomial). |
gf2::BitPolynomial::size |
Returns the number of polynomial coefficients. |
gf2::BitPolynomial::is_zero |
Returns true if this is some form of the zero polynomial. |
gf2::BitPolynomial::is_non_zero |
Returns true if this is not some form of the zero polynomial. |
gf2::BitPolynomial::is_one |
Returns true if this is the polynomial |
gf2::BitPolynomial::is_constant |
Returns true if this is the polynomial |
gf2::BitPolynomial::is_monic |
Returns true if there are no high order zero coefficients. |
gf2::BitPolynomial::is_empty |
Returns true if this polynomial has no coefficients |
A polynomial is considered monic if its leading coefficient (the coefficient of the highest-degree term) is 1.
For example, the polynomial
There are methods to access and modify the polynomial coefficients either individually or as a whole:
| Method Name | Description |
|---|---|
gf2::BitPolynomial::operator[]() const |
Returns a polynomial coefficient as a read-only boolean. |
gf2::BitPolynomial::operator[]() |
Returns a polynomial coefficient as a read-write gf2::BitRef. |
gf2::BitPolynomial::coefficients const |
Returns a read-only reference to the coefficient bit-vector. |
gf2::BitPolynomial::coefficients |
Returns a read-write reference to the coefficient bit-vector. |
gf2::BitPolynomial::copy_coefficients |
Copies the elements from the passed bit-store to the coefficient bit-vector. |
gf2::BitPolynomial::move_coefficients |
Moves the elements from the passed bit-store to the coefficient bit-vector. |
gf2::BitPolynomial::clear |
Sets the polynomial back to |
gf2::BitPolynomial::resize |
Resizes the polynomial to have the n coefficients (added ones are zeros). |
gf2::BitPolynomial::shrink_to_fit |
Calls gf2::BitVector::shrink_to_fit on the coefficient bit-vector. |
gf2::BitPolynomial::make_monic |
Kills any high order zero coefficients to make the polynomial monic. |
We have methods to extract sub-polynomials:
| Method Name | Description |
|---|---|
gf2::BitPolynomial::sub_polynomial |
Extract a bit-polynomial that is a copy of some low degree terms. |
gf2::BitPolynomial::split |
Extract two bit-polynomials lo and hi, lo is a copy of low degree terms and hi is the rest. |
Both methods can be passed pre-allocated polynomial(s) to store the result(s) to avoid unnecessary allocations. For example:
auto p = gf2::BitPolynomial<>::random(100); // Random degree 100 polynomial, so 101 coefficients.
auto [l, h] = p.split(50); // First 51 coefficients in lo, rest in hi.On return, l will be a polynomial of degree at most 50 (so have at most 51 coefficients) and h will be a polynomial of degree at most 49 (so have at most 50 coefficients). The original polynomial can be reconstructed as:
The same code can be written to avoid allocations as:
auto p = gf2::BitPolynomial<>::random(100); // Random degree
BitPolynomial<> l, h;
p.split(50, l, h); // First 51 coefficients in lo, rest in hi.This is useful if the split operation is being performed repeatedly in an algorithm.
We have all the usual arithmetic operations defined for gf2::BitPolynomial objects where the addition and subtraction operations are identical since we are working over GF(2).
| Method Name | Description |
|---|---|
gf2::BitPolynomial::operator+=() |
In-place addition with another bit-polynomial. |
gf2::BitPolynomial::operator-=() |
In-place subtraction with another bit-polynomial. |
gf2::BitPolynomial::operator*=() |
In-place multiplication by another bit-polynomial. |
gf2::BitPolynomial::operator+() |
Adds another polynomial to this one and returns the result as a new bit-polynomial. |
gf2::BitPolynomial::operator-() |
Subtracts another polynomial from this one and returns the result as a new bit-polynomial. |
gf2::BitPolynomial::operator*() |
Multiplies this and another polynomial and returns the result as a new bit-polynomial. |
TODO: As yet, we have not implemented polynomial division.
Note
Considerable speed improvements are possible by using carryless multiplication algorithms. However, for now at least, those depend on using platform-specific intrinsics which complicates the library and, in particular, testing the library across multiple platforms.
So for the time being, we stick to a more portable convolution approach using gf2::convolve on the coefficient bit-vectors.
However, we do have a couple of "fast" methods for common arithmetic operations:
| Method Name | Description |
|---|---|
gf2::BitPolynomial::squared |
Computes the polynomial |
gf2::BitPolynomial::times_x_to_the |
Performs the in-place operation |
The squaring operation is optimised since in GF(2), squaring a polynomial simply involves inserting zero coefficients between each existing coefficient (see gf2::riffle).
The gf2::BitPolynomial::squared can be passed a pre-allocated polynomial to store the result --- this is important for algorithms that require repeated squaring to avoid unnecessary allocations. See for example the modular reduction technical note for details.
Multiplication by
Those methods are much faster than using the general multiplication operator
There are methods to evaluate a bit-polynomial for a scalar value or for any square bit-matrix:
| Method Name | Description |
|---|---|
gf2::BitPolynomial::operator()(bool x) |
Evaluates the polynomial at the passed bit value x. |
gf2::BitPolynomial::operator()(const BitMatrix<Word>& M) |
Evaluates the polynomial at the passed square bit-matrix M. |
Matrix evaluation uses Horner's method to evaluate p(M) where M is a square matrix.
The result is returned as a new bit-matrix.
We have a method to compute
| Method Name | Description |
|---|---|
gf2::BitPolynomial::reduce_x_to_the |
Returns the polynomial |
This method can handle very large values of
See the modular reduction technical note for more details.
The following methods return a string representation for a bit-polynomial.
| Method | Description |
|---|---|
gf2::BitPolynomial::to_string |
Returns a string representation where zero coefficients are not shown. |
gf2::BitPolynomial::to_full_string |
Returns a string representation where zero coefficients are all shown.. |
gf2::BitPolynomial::operator<<(std::ostream&) |
The usual output stream output stream operator for bit-polynomials. |
struct std::formatter<gf2::BitPolynomial> |
Specialisation of std::formatter for bit-polynomials. |
The to_string and to_full_string methods can be passed a string argument to specify the variable name.
The default variable name is x.
auto p = BitPolynomial<>::ones(3);
assert_eq(p.to_string(), "1 + x + x^2 + x^3");
assert_eq(p.to_string("M"), "1 + M + M^2 + M^3");For std::formatter you can set the variable name using a format specifier:
auto p = BitPolynomial<>::ones(2);
std::println("{:x}", p); // prints "1 + x + x^2"
std::println("{:M}", p); // prints "1 + M + M^2"
std::println("{:mat}", p); // prints "1 + mat + mat^2"-
gf2::BitPolynomialfor detailed documentation of all class methods. -
BitStorefor the concept API shared by all bit-stores. -
BitArrayfor fixed-size vectors of bits. -
BitVectorfor dynamically-sized vectors of bits. -
BitSpanfor non-owning views into any bit-store. -
BitMatrixfor matrices of bits. -
Modular Reduction for details on the modular reduction
$x^N \bmod{p(x)}$ .