2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
51#ifndef POLYNOMIALS_HPP
52#define POLYNOMIALS_HPP
54#include <initializer_list>
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
80template <ComponentType T>
82template <CoefficientType T>
85template <CoefficientType T>
88template <CoefficientType T>
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118template <CoefficientType T>
120 template <ReliablyComparableType U>
129
130
142
143
144
145
146
153
154
155
156
157
158
159
160
166
167
168
169
170
176
177
193
194
207
208
209
210
211
217
218
226
227
228
229
230
234
235
236
237
242
243
244
245
246
247
255
256
257
258
259
260
268
269
270
271
278
279
282
283
284
285
286
287
293
294
297
298
299
300
301
302
303
308
309
310
311
312
313
314
321
322
325
326
327
328
329
337
338
339
340
345
346
347
348
353
354
355
356
360 constexpr bool is_empty()
const noexcept {
return data.empty(); }
363
364
365
366
375
376
377
378
387
388
389
390
399
400
401
402
403
404
405
406
412 if (
t == 0)
return false;
413 if (
t == 1)
return true;
415 const auto&
g = *
this;
425 if (
e >> 1)
a = (
a *
a) %
g;
442 while (
m %
p == 0)
m /=
p;
462
463
466
467
468
469
470
471 template <
typename U>
476
477
478
479
480
481 template <
typename U>
489
490
491
496
497
498
499
515 mutable details::Cache<details::CacheEntry<Weight, size_t>> cache;
517 constexpr size_t calculate_weight()
const
539template <CoefficientType T>
541 for (size_t i = 0; i < data.size(); ++i) data[i] = v[i];
545template <CoefficientType T>
550 cache.
template set<Weight>(0);
552 cache.
template set<Weight>(1);
556template <CoefficientType T>
558 if (
this == &rhs)
return *
this;
559 if (rhs.data.empty()) {
569template <CoefficientType T>
571 if (
this == &rhs)
return *
this;
572 if (rhs.data.empty()) {
577 data = std::move(rhs.data);
578 cache = std::move(rhs.cache);
598template <CoefficientType T>
601 std::ranges::for_each(res.data, [](T& c) { c = -c; });
605template <CoefficientType T>
607 std::ranges::for_each(data, [](T& c) { c = -c; });
608 return std::move(*
this);
611template <CoefficientType T>
613 if (data.empty())
throw std::invalid_argument(
"trying to evaluate empty polynomial");
614 if (data.size() == 1)
return data.front();
616 return std::accumulate(data.crbegin() + 1, data.crend(), data.back(),
617 [&s](
const T& acc,
const T& coeff) {
return acc * s + coeff; });
620template <CoefficientType T>
622 if (data.size() < rhs.data.size()) data.resize(rhs.data.size(), T(0));
623 std::transform(data.begin(), data.begin() + rhs.data.size(), rhs.data.begin(), data.begin(), std::plus<T>{});
629template <CoefficientType T>
631 if (data.size() < rhs.data.size()) data.resize(rhs.data.size(), T(0));
632 std::transform(data.begin(), data.begin() + rhs.data.size(), rhs.data.begin(), data.begin(), std::minus<T>{});
638template <CoefficientType T>
640 if (is_empty() || rhs.is_empty())
throw std::invalid_argument(
"trying to multiply with empty polynomial");
641 std::vector<T> res(data.size() + rhs.data.size() - 1, T(0));
642 for (size_t i = 0; i < data.size(); ++i) {
643 for (size_t j = 0; j < rhs.data.size(); ++j) res[i + j] += data[i] * rhs.data[j];
645 data = std::move(res);
651template <CoefficientType T>
661template <CoefficientType T>
686template <CoefficientType T>
689 cache.
template set<Weight>(0);
693 std::ranges::for_each(data, [&s](T& c) { c *= s; });
698template <CoefficientType T>
700 if constexpr (FieldType<T>) {
701 if (T::get_characteristic() != 0) n = n % T::get_characteristic();
704 cache.
template set<Weight>(0);
708 std::ranges::for_each(data, [&n](T& c) { c *= n; });
713template <CoefficientType T>
722template <CoefficientType T>
750template <CoefficientType T>
754 if constexpr (FieldType<T>) {
755 std::ranges::for_each(data, std::mem_fn(&T::randomize));
757 data.back().randomize();
758 }
while (data.back() == zero);
759 }
else if constexpr (std::same_as<T,
double>) {
760 std::uniform_real_distribution<
double> dist(-1.0, 1.0);
761 std::ranges::for_each(data, [&](
double& val) { val = dist(gen()); });
763 data.back() = dist(gen());
764 }
while (data.back() == zero);
765 }
else if constexpr (std::same_as<T, std::complex<
double>>) {
766 std::uniform_real_distribution<
double> dist(-1.0, 1.0);
767 std::ranges::for_each(data,
768 [&](std::complex<
double>& val) { val = std::complex<
double>(dist(gen()), dist(gen())); });
770 data.back() = std::complex<
double>(dist(gen()), dist(gen()));
771 }
while (data.back() == zero);
772 }
else if constexpr (SignedIntType<T>) {
773 std::uniform_int_distribution<
long long> dist(-100, 100);
774 std::ranges::for_each(data, [&](T& val) { val = T(dist(gen())); });
776 data.back() = dist(gen());
777 }
while (data.back() == zero);
783template <CoefficientType T>
789 if (
s == 0)
return *
this;
791 if (
d == 0 ||
s >
d) {
812template <CoefficientType T>
818 if (
s == 0)
return *
this;
820 if (
d == 0 ||
s >
d) {
843template <CoefficientType T>
852template <CoefficientType T>
854 Vector<T> res(data.size());
855 std::copy(data.begin(), data.end(), res.data.begin());
856 res.cache.invalidate();
860template <CoefficientType T>
874template <CoefficientType T>
880 "trying to access non-existent element (trailing "
884 "trying to access non-existent element (trailing "
885 "coefficient of zero polynomial)");
889template <CoefficientType T>
892 throw std::invalid_argument(
893 "trying to access non-existent element (leading "
954 if (
s == 0 ||
is_zero())
return *
this;
962 if (
s == 0)
return *
this;
995#ifdef CECCO_ERASURE_SUPPORT
1359 if (
i > 1)
os <<
"^" <<
i;
1369
1370
1371
1372
1373
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1441
1442
1443
1444
1445
1451 throw std::
invalid_argument(
"trying to calculate polynomial GCD but didn't provide any polynomials");
1470
1471
1472
1473
1474
1480 throw std::
invalid_argument(
"trying to calculate polynomial LCM but didn't provide any polynomials");
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1508
1509
1510
1511
1512
1513
1514
1515
1518 if constexpr (
p == 2) {
1519 if constexpr (
m == 1)
1521 else if constexpr (
m == 2)
1523 else if constexpr (
m == 3)
1524 return {1, 1, 0, 1};
1525 else if constexpr (
m == 4)
1526 return {1, 1, 0, 0, 1};
1527 else if constexpr (
m == 5)
1528 return {1, 0, 1, 0, 0, 1};
1529 else if constexpr (
m == 6)
1530 return {1, 1, 0, 1, 1, 0, 1};
1531 else if constexpr (
m == 7)
1532 return {1, 1, 0, 0, 0, 0, 0, 1};
1533 else if constexpr (
m == 8)
1534 return {1, 0, 1, 1, 1, 0, 0, 0, 1};
1535 else if constexpr (
m == 9)
1536 return {1, 0, 0, 0, 1, 0, 0, 0, 0, 1};
1537 else if constexpr (
m == 10)
1538 return {1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1};
1539 else if constexpr (
m == 11)
1540 return {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
1541 else if constexpr (
m == 12)
1542 return {1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1};
1543 else if constexpr (
m == 13)
1544 return {1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
1545 }
else if constexpr (
p == 3) {
1546 if constexpr (
m == 1)
1548 else if constexpr (
m == 2)
1550 else if constexpr (
m == 3)
1551 return {1, 2, 0, 1};
1552 else if constexpr (
m == 4)
1553 return {2, 0, 0, 2, 1};
1554 else if constexpr (
m == 5)
1555 return {1, 2, 0, 0, 0, 1};
1556 else if constexpr (
m == 6)
1557 return {2, 2, 1, 0, 2, 0, 1};
1558 else if constexpr (
m == 7)
1559 return {1, 0, 2, 0, 0, 0, 0, 1};
1560 else if constexpr (
m == 8)
1561 return {2, 2, 2, 0, 1, 2, 0, 0, 1};
1562 }
else if constexpr (
p == 5) {
1563 if constexpr (
m == 1)
1565 else if constexpr (
m == 2)
1567 else if constexpr (
m == 3)
1568 return {3, 3, 0, 1};
1569 else if constexpr (
m == 4)
1570 return {2, 4, 4, 0, 1};
1571 else if constexpr (
m == 5)
1572 return {3, 4, 0, 0, 0, 1};
1573 }
else if constexpr (
p == 7) {
1574 if constexpr (
m == 1)
1576 else if constexpr (
m == 2)
1578 else if constexpr (
m == 3)
1579 return {4, 0, 6, 1};
1580 else if constexpr (
m == 4)
1581 return {3, 4, 5, 0, 1};
1582 }
else if constexpr (
p == 11) {
1583 if constexpr (
m == 1)
1585 else if constexpr (
m == 2)
1587 else if constexpr (
m == 3)
1588 return {9, 2, 0, 1};
1589 else if constexpr (
m == 4)
1590 return {2, 10, 8, 0, 1};
1591 }
else if constexpr (
p == 13) {
1592 if constexpr (
m == 1)
1594 else if constexpr (
m == 2)
1596 else if constexpr (
m == 3)
1597 return {11, 2, 0, 1};
1598 }
else if constexpr (
p == 17) {
1599 if constexpr (
m == 1)
1601 else if constexpr (
m == 2)
1603 else if constexpr (
m == 3)
1604 return {14, 1, 0, 1};
1605 }
else if constexpr (
p == 19) {
1606 if constexpr (
m == 1)
1608 else if constexpr (
m == 2)
1610 else if constexpr (
m == 3)
1611 return {17, 4, 0, 1};
1612 }
else if constexpr (
p == 23) {
1613 if constexpr (
m == 1)
1615 else if constexpr (
m == 2)
1617 }
else if constexpr (
p == 29) {
1618 if constexpr (
m == 1)
1620 else if constexpr (
m == 2)
1622 }
else if constexpr (
p == 31) {
1623 if constexpr (
m == 1)
1625 else if constexpr (
m == 2)
1627 }
else if constexpr (
p == 37) {
1628 if constexpr (
m == 1)
1630 else if constexpr (
m == 2)
1632 }
else if constexpr (
p == 41) {
1633 if constexpr (
m == 1)
1635 else if constexpr (
m == 2)
1637 }
else if constexpr (
p == 43) {
1638 if constexpr (
m == 1)
1640 else if constexpr (
m == 2)
1642 }
else if constexpr (
p == 47) {
1643 if constexpr (
m == 1)
1645 else if constexpr (
m == 2)
1647 }
else if constexpr (
p == 53) {
1648 if constexpr (
m == 1)
1650 else if constexpr (
m == 2)
1652 }
else if constexpr (
p == 59) {
1653 if constexpr (
m == 1)
1655 else if constexpr (
m == 2)
1657 }
else if constexpr (
p == 61) {
1658 if constexpr (
m == 1)
1660 else if constexpr (
m == 2)
1662 }
else if constexpr (
p == 67) {
1663 if constexpr (
m == 1)
1665 else if constexpr (
m == 2)
1667 }
else if constexpr (
p == 71) {
1668 if constexpr (
m == 1)
1670 else if constexpr (
m == 2)
1672 }
else if constexpr (
p == 73) {
1673 if constexpr (
m == 1)
1675 else if constexpr (
m == 2)
1677 }
else if constexpr (
p == 79) {
1678 if constexpr (
m == 1)
1680 else if constexpr (
m == 2)
1682 }
else if constexpr (
p == 83) {
1683 if constexpr (
m == 1)
1685 else if constexpr (
m == 2)
1687 }
else if constexpr (
p == 89) {
1688 if constexpr (
m == 1)
1690 else if constexpr (
m == 2)
1692 }
else if constexpr (
p == 97) {
1693 if constexpr (
m == 1)
1695 else if constexpr (
m == 2)
1703
1704
1705
1706
1707
1708
1719
1720
1721
1722
1723
1724
Univariate polynomial p(x) = a₀ + a₁x + … + aₙxⁿ over a CECCO::CoefficientType.
constexpr Polynomial< T > & add_to_coefficient(size_t i, U &&c)
constexpr Polynomial operator+() &&noexcept
Unary + (rvalue): returns the rvalue itself.
std::pair< Polynomial< T >, Polynomial< T > > poly_long_div(const Polynomial< T > &rhs) const
Long division: returns (q, r) with *this == q · rhs + r and r == 0 or deg(r) < deg(rhs).
Polynomial(const Vector< T > &v)
From a coefficient vector: v[i] becomes the coefficient of x^i.
constexpr Polynomial & operator+=(const Polynomial &rhs)
Coefficient-wise addition; expands storage if rhs has higher degree, then prunes.
Polynomial & operator/=(const T &s)
Divide every coefficient by the scalar s.
const T & trailing_coefficient() const
Coefficient of the lowest non-zero power.
constexpr Polynomial & set_coefficient(size_t i, U &&c)
Set the coefficient of x^i to c; grows the polynomial if i > degree.
constexpr T operator[](size_t i) const
Coefficient of x^i; returns T(0) for i > degree.
Vector< T > get_coefficients() const
Coefficient vector (length = number of stored coefficients; 0 for an empty polynomial).
Polynomial & Hasse_differentiate(size_t s)
In-place s-th Hasse derivative (= classical s-th derivative divided by s!).
Polynomial & operator/=(const Polynomial &rhs)
Polynomial division: *this becomes the quotient of (*this) / rhs.
T operator()(const T &s) const
Evaluate at s using Horner's method (O(n)).
const T & leading_coefficient() const
Coefficient of the highest non-zero power.
constexpr Polynomial & operator*=(const T &s)
Multiply every coefficient by the scalar s.
constexpr Polynomial & shift_down(size_t s)
Floor-divide by x^s by dropping the s lowest coefficients; degree < s yields the zero polynomial.
constexpr Polynomial operator+() const &
Unary + (lvalue): returns a copy.
constexpr Polynomial operator-() const &
Unary − (lvalue): returns a new polynomial with each coefficient negated.
constexpr Polynomial(Polynomial &&other) noexcept
constexpr Polynomial(int e)
Constant polynomial from an int (constructs T(e)).
constexpr bool is_empty() const noexcept
True iff *this has no coefficients (distinct from the zero polynomial).
Polynomial & differentiate(size_t s)
In-place classical s-th derivative.
constexpr Polynomial & reciprocal()
Reciprocal: reverse coefficients, sending p(x) to xⁿ · p(1/x).
constexpr Polynomial & operator=(Polynomial &&rhs) noexcept
constexpr Polynomial() noexcept=default
Default constructor: empty polynomial (no coefficients; distinct from the zero polynomial).
size_t degree() const
Degree max{i : aᵢ ≠ 0}.
constexpr Polynomial & operator*=(size_t n)
Multiply every coefficient by the integer n; reduces n modulo characteristic if available.
constexpr Polynomial & normalize()
Make monic by dividing every coefficient by the leading one (no-op on zero or already-monic).
Polynomial & randomize(size_t d)
Replace *this with a random polynomial of degree exactly d.
size_t trailing_degree() const
Trailing degree min{i : aᵢ ≠ 0}.
Polynomial & operator%=(const Polynomial &rhs)
Polynomial remainder: *this becomes (*this) mod rhs.
constexpr Polynomial(const T &e)
Constant polynomial from a coefficient.
bool is_zero() const
True iff *this is the zero polynomial (one coefficient, equal to T(0)).
friend constexpr bool operator==(const Polynomial< U > &lhs, const Polynomial< U > &rhs)
constexpr Polynomial(const Polynomial &other)
constexpr Polynomial & shift_up(size_t s)
Multiply by x^s by prepending s zero coefficients (the zero polynomial is unchanged).
constexpr Polynomial operator-() &&
Unary − (rvalue): negates coefficients in place.
constexpr Polynomial & operator-=(const Polynomial &rhs)
Coefficient-wise subtraction; expands storage if rhs has higher degree, then prunes.
constexpr Polynomial & operator*=(const Polynomial &rhs)
Polynomial multiplication by convolution (O(n²)).
constexpr Polynomial & operator=(const T &rhs)
Assign a scalar: replace *this with the constant polynomial rhs.
constexpr Polynomial & operator=(const Polynomial< T > &rhs)
Vector v = (v₀, v₁, …, vₙ₋₁) over a CECCO::ComponentType.
Provides a framework for error correcting codes.
const Polynomial< T > & ZeroPolynomial()
Constant polynomial 0 (cached).