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 <ComponentType T>
85template <ComponentType T>
87template <ComponentType T>
90template <ComponentType T>
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120template <ComponentType T>
130
131
143
144
145
146
147
154
155
156
157
158
159
160
161
167
168
169
170
171
177
178
194
195
208
209
210
211
212
218
219
227
228
229
230
231
235
236
237
238
243
244
245
246
247
248
256
257
258
259
260
261
269
270
271
272
279
280
283
284
285
286
287
288
294
295
298
299
300
301
302
303
304
309
310
311
312
313
314
315
322
323
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
409 if (
d == 0)
return false;
410 if (
d == 1)
return true;
426 if (((*
this) %
p).
is_zero())
return false;
443
444
447
448
449
450
451
452 template <
typename U>
457
458
459
460
461
462 template <
typename U>
482 mutable details::Cache<details::CacheEntry<Weight, size_t>> cache;
484 constexpr size_t calculate_weight()
const
501template <ComponentType T>
503 for (size_t i = 0; i < data.size(); ++i) data[i] = v[i];
507template <ComponentType T>
512 cache.
template set<Weight>(0);
514 cache.
template set<Weight>(1);
518template <ComponentType T>
520 if (
this == &rhs)
return *
this;
521 if (rhs.data.empty()) {
531template <ComponentType T>
533 if (
this == &rhs)
return *
this;
534 if (rhs.data.empty()) {
539 data = std::move(rhs.data);
540 cache = std::move(rhs.cache);
560template <ComponentType T>
563 std::ranges::for_each(res.data, [](T& c) { c = -c; });
567template <ComponentType T>
569 std::ranges::for_each(data, [](T& c) { c = -c; });
571 return std::move(*
this);
574template <ComponentType T>
576 if (data.empty())
throw std::invalid_argument(
"trying to evaluate empty polynomial");
577 if (data.size() == 1)
return data.front();
580 return std::accumulate(data.crbegin() + 1, data.crend(), data.back(),
581 [&s](
const T& acc,
const T& coeff) {
return acc * s + coeff; });
584template <ComponentType T>
586 if (data.size() < rhs.data.size()) data.resize(rhs.data.size());
587 std::transform(data.begin(), data.begin() + rhs.data.size(), rhs.data.begin(), data.begin(), std::plus<T>{});
593template <ComponentType T>
595 if (data.size() < rhs.data.size()) data.resize(rhs.data.size());
596 std::transform(data.begin(), data.begin() + rhs.data.size(), rhs.data.begin(), data.begin(), std::minus<T>{});
602template <ComponentType T>
604 if (is_empty() || rhs.is_empty())
throw std::invalid_argument(
"trying to multiply with empty polynomial");
606 res.data.resize(data.size() + rhs.data.size() - 1);
607 for (size_t i = 0; i < data.size(); ++i) {
608 for (size_t j = 0; j < rhs.data.size(); ++j) res.add_to_coefficient(i + j, data[i] * rhs.data[j]);
610 data = std::move(res.data);
616template <ComponentType T>
626template <ComponentType T>
650template <ComponentType T>
653 cache.
template set<Weight>(0);
657 std::ranges::for_each(data, [&s](T& c) { c *= s; });
663template <ComponentType T>
681template <ComponentType T>
683 if (s == T(0))
throw std::invalid_argument(
"division by zero (polynomial)");
684 std::ranges::for_each(data, [&s](T& c) { c /= s; });
689template <ComponentType T>
715template <ComponentType T>
718 if constexpr (FieldType<T>) {
719 std::ranges::for_each(data, std::mem_fn(&T::randomize));
721 data.back().randomize();
722 }
while (data.back() == T(0));
723 }
else if constexpr (std::same_as<T,
double>) {
724 std::uniform_real_distribution<
double> dist(-1.0, 1.0);
725 std::ranges::for_each(data, [&](
double& val) { val = dist(gen()); });
727 data.back() = dist(gen());
728 }
while (data.back() == T(0));
729 }
else if constexpr (std::same_as<T, std::complex<
double>>) {
730 std::uniform_real_distribution<
double> dist(-1.0, 1.0);
731 std::ranges::for_each(data,
732 [&](std::complex<
double>& val) { val = std::complex<
double>(dist(gen()), dist(gen())); });
734 data.back() = std::complex<
double>(dist(gen()), dist(gen()));
735 }
while (data.back() == T(0));
736 }
else if constexpr (SignedIntType<T>) {
737 std::uniform_int_distribution<
long long> dist(-100, 100);
738 std::ranges::for_each(data, [&](T& val) { val = T(dist(gen())); });
740 data.back() = dist(gen());
741 }
while (data.back() == T(0));
747template <ComponentType T>
753 if (
s == 0)
return *
this;
755 if (
d == 0 ||
s >
d) {
780template <ComponentType T>
786 if (
s == 0)
return *
this;
788 if (
d == 0 ||
s >
d) {
800template <ComponentType T>
808template <ComponentType T>
810 Vector<T> res(data.size());
811 for (size_t i = 0; i < data.size(); ++i) res.set_component(i, data[i]);
815template <ComponentType T>
821 if (
d == 0)
return 0;
827template <ComponentType T>
833 "trying to access non-existent element (trailing "
838template <ComponentType T>
841 throw std::invalid_argument(
842 "trying to access non-existent element (leading "
919#ifdef CECCO_ERASURE_SUPPORT
1227 if (
coeff !=
T(1) ||
i == 0) {
1232 if (
i > 1)
os <<
"^" <<
i;
1259
1260
1261
1262
1263
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1304 if (
s !=
nullptr &&
t !=
nullptr) {
1335
1336
1337
1338
1339
1345 throw std::
invalid_argument(
"trying to calculate polynomial GCD but didn't provide any polynomials");
1364
1365
1366
1367
1368
1374 throw std::
invalid_argument(
"trying to calculate polynomial LCM but didn't provide any polynomials");
1385
1386
1387
1388
1389
1390
1391
1392
1399
1400
1401
1402
1403
1404
1405
1406
1409 if constexpr (
p == 2) {
1410 if constexpr (
m == 1)
1412 else if constexpr (
m == 2)
1414 else if constexpr (
m == 3)
1415 return {1, 1, 0, 1};
1416 else if constexpr (
m == 4)
1417 return {1, 1, 0, 0, 1};
1418 else if constexpr (
m == 5)
1419 return {1, 0, 1, 0, 0, 1};
1420 else if constexpr (
m == 6)
1421 return {1, 1, 0, 1, 1, 0, 1};
1422 else if constexpr (
m == 7)
1423 return {1, 1, 0, 0, 0, 0, 0, 1};
1424 else if constexpr (
m == 8)
1425 return {1, 0, 1, 1, 1, 0, 0, 0, 1};
1426 else if constexpr (
m == 9)
1427 return {1, 0, 0, 0, 1, 0, 0, 0, 0, 1};
1428 else if constexpr (
m == 10)
1429 return {1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1};
1430 else if constexpr (
m == 11)
1431 return {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
1432 else if constexpr (
m == 12)
1433 return {1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1};
1434 else if constexpr (
m == 13)
1435 return {1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
1436 }
else if constexpr (
p == 3) {
1437 if constexpr (
m == 1)
1439 else if constexpr (
m == 2)
1441 else if constexpr (
m == 3)
1442 return {1, 2, 0, 1};
1443 else if constexpr (
m == 4)
1444 return {2, 0, 0, 2, 1};
1445 else if constexpr (
m == 5)
1446 return {1, 2, 0, 0, 0, 1};
1447 else if constexpr (
m == 6)
1448 return {2, 2, 1, 0, 2, 0, 1};
1449 else if constexpr (
m == 7)
1450 return {1, 0, 2, 0, 0, 0, 0, 1};
1451 else if constexpr (
m == 8)
1452 return {2, 2, 2, 0, 1, 2, 0, 0, 1};
1453 }
else if constexpr (
p == 5) {
1454 if constexpr (
m == 1)
1456 else if constexpr (
m == 2)
1458 else if constexpr (
m == 3)
1459 return {3, 3, 0, 1};
1460 else if constexpr (
m == 4)
1461 return {2, 4, 4, 0, 1};
1462 else if constexpr (
m == 5)
1463 return {3, 4, 0, 0, 0, 1};
1464 }
else if constexpr (
p == 7) {
1465 if constexpr (
m == 1)
1467 else if constexpr (
m == 2)
1469 else if constexpr (
m == 3)
1470 return {4, 0, 6, 1};
1471 else if constexpr (
m == 4)
1472 return {3, 4, 5, 0, 1};
1473 }
else if constexpr (
p == 11) {
1474 if constexpr (
m == 1)
1476 else if constexpr (
m == 2)
1478 else if constexpr (
m == 3)
1479 return {9, 2, 0, 1};
1480 else if constexpr (
m == 4)
1481 return {3, 4, 5, 0, 1};
1482 }
else if constexpr (
p == 13) {
1483 if constexpr (
m == 1)
1485 else if constexpr (
m == 2)
1487 else if constexpr (
m == 3)
1488 return {11, 2, 0, 1};
1489 }
else if constexpr (
p == 17) {
1490 if constexpr (
m == 1)
1492 else if constexpr (
m == 2)
1494 else if constexpr (
m == 3)
1495 return {14, 1, 0, 1};
1496 }
else if constexpr (
p == 19) {
1497 if constexpr (
m == 1)
1499 else if constexpr (
m == 2)
1501 else if constexpr (
m == 3)
1502 return {17, 4, 0, 1};
1503 }
else if constexpr (
p == 23) {
1504 if constexpr (
m == 1)
1506 else if constexpr (
m == 2)
1508 }
else if constexpr (
p == 29) {
1509 if constexpr (
m == 1)
1511 else if constexpr (
m == 2)
1513 }
else if constexpr (
p == 31) {
1514 if constexpr (
m == 1)
1516 else if constexpr (
m == 2)
1518 }
else if constexpr (
p == 37) {
1519 if constexpr (
m == 1)
1521 else if constexpr (
m == 2)
1523 }
else if constexpr (
p == 43) {
1524 if constexpr (
m == 1)
1526 else if constexpr (
m == 2)
1528 }
else if constexpr (
p == 47) {
1529 if constexpr (
m == 1)
1531 else if constexpr (
m == 2)
1533 }
else if constexpr (
p == 53) {
1534 if constexpr (
m == 1)
1536 else if constexpr (
m == 2)
1538 }
else if constexpr (
p == 59) {
1539 if constexpr (
m == 1)
1541 else if constexpr (
m == 2)
1543 }
else if constexpr (
p == 61) {
1544 if constexpr (
m == 1)
1546 else if constexpr (
m == 2)
1548 }
else if constexpr (
p == 67) {
1549 if constexpr (
m == 1)
1551 else if constexpr (
m == 2)
1553 }
else if constexpr (
p == 71) {
1554 if constexpr (
m == 1)
1556 else if constexpr (
m == 2)
1558 }
else if constexpr (
p == 73) {
1559 if constexpr (
m == 1)
1561 else if constexpr (
m == 2)
1563 }
else if constexpr (
p == 79) {
1564 if constexpr (
m == 1)
1566 else if constexpr (
m == 2)
1568 }
else if constexpr (
p == 83) {
1569 if constexpr (
m == 1)
1571 else if constexpr (
m == 2)
1573 }
else if constexpr (
p == 89) {
1574 if constexpr (
m == 1)
1576 else if constexpr (
m == 2)
1578 }
else if constexpr (
p == 97) {
1579 if constexpr (
m == 1)
1581 else if constexpr (
m == 2)
1589
1590
1591
1592
1599
1600
1601
1602
1603
1604
Univariate polynomial p(x) = a₀ + a₁x + … + aₙxⁿ over a CECCO::ComponentType.
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.
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 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.
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.
Polynomial & operator/=(const T &s)
Divide every coefficient by the scalar s.
size_t trailing_degree() const
Trailing degree min{i : aᵢ ≠ 0}.
friend bool operator==(const Polynomial &lhs, const Polynomial &rhs)
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)).
constexpr Polynomial(const Polynomial &other)
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.
Polynomial< T > ZeroPolynomial()
Constant polynomial 0 (cached).
constexpr bool operator==(const Polynomial< T > &lhs, const Polynomial< T > &rhs)