Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
polynomial_test.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 MIT License (see tpl_polynomial.H for full text)
13*/
14
15# include <gtest/gtest.h>
16# include <chrono>
17# include <cmath>
18# include <limits>
19# include <random>
20# include <string>
21# include <sstream>
22# include <stdexcept>
23# include <tpl_polynomial.H>
24
25using namespace Aleph;
26
27namespace {
28
30make_random_polynomial(std::mt19937 & rng, size_t max_degree = 4,
31 int min_coeff = -2, int max_coeff = 2,
32 bool require_nonzero = false)
33{
34 std::uniform_int_distribution<size_t> degree_dist(0, max_degree);
35 std::uniform_int_distribution<int> coeff_dist(min_coeff, max_coeff);
36
37 while (true)
38 {
39 const size_t degree = degree_dist(rng);
40 DynList<double> coeffs;
41
42 for (size_t exp = 0; exp <= degree; ++exp)
43 coeffs.append(static_cast<double>(coeff_dist(rng)));
44
45 Polynomial p(coeffs);
46 if (not require_nonzero or not p.is_zero())
47 return p;
48 }
49}
50
51} // namespace
52
53// ===================================================================
54// Construction
55// ===================================================================
56
58{
59 Polynomial p;
61 EXPECT_EQ(p.degree(), 0u);
62 EXPECT_EQ(p.num_terms(), 0u);
63}
64
66{
67 const auto value = std::numeric_limits<long long>::min();
68 const auto expected = static_cast<uint64_t>(std::numeric_limits<long long>::max()) + 1ULL;
70}
71
73{
74 Polynomial p(5.0);
76 EXPECT_EQ(p.degree(), 0u);
77 EXPECT_EQ(p.num_terms(), 1u);
78 EXPECT_DOUBLE_EQ(p[0], 5.0);
80}
81
87
89{
90 Polynomial p(3.0, 5); // 3x^5
91 EXPECT_EQ(p.degree(), 5u);
92 EXPECT_EQ(p.num_terms(), 1u);
93 EXPECT_DOUBLE_EQ(p[5], 3.0);
94 EXPECT_DOUBLE_EQ(p[0], 0.0);
96}
97
99{
100 Polynomial p({1, 0, 3}); // 1 + 3x^2
101 EXPECT_EQ(p.degree(), 2u);
102 EXPECT_EQ(p.num_terms(), 2u);
103 EXPECT_DOUBLE_EQ(p[0], 1.0);
104 EXPECT_DOUBLE_EQ(p[1], 0.0);
105 EXPECT_DOUBLE_EQ(p[2], 3.0);
106}
107
109{
110 DynList<double> l = {2, 3, 0, 5};
111 Polynomial p(l); // 2 + 3x + 5x^3
112 EXPECT_EQ(p.degree(), 3u);
113 EXPECT_EQ(p.num_terms(), 3u);
114 EXPECT_DOUBLE_EQ(p[0], 2.0);
115 EXPECT_DOUBLE_EQ(p[1], 3.0);
116 EXPECT_DOUBLE_EQ(p[3], 5.0);
117}
118
120{
122 terms.append({0, 1.0});
123 terms.append({100, 2.0});
124 Polynomial p(terms); // 1 + 2x^100
125 EXPECT_EQ(p.degree(), 100u);
126 EXPECT_EQ(p.num_terms(), 2u);
127 EXPECT_DOUBLE_EQ(p[0], 1.0);
128 EXPECT_DOUBLE_EQ(p[100], 2.0);
129}
130
132{
134 terms.append({2, 3.0});
135 terms.append({0, 1.0});
136 terms.append({2, -1.5});
137 terms.append({2, -1.5});
138
139 Polynomial p(terms);
140 EXPECT_EQ(p.degree(), 0u);
141 EXPECT_EQ(p.num_terms(), 1u);
142 EXPECT_DOUBLE_EQ(p[0], 1.0);
143 EXPECT_DOUBLE_EQ(p[2], 0.0);
144}
145
147{
148 Polynomial p({0, 0, 0});
149 EXPECT_TRUE(p.is_zero());
150}
151
153{
154 Polynomial p({1, 2, 3});
155 Polynomial q(p);
156 EXPECT_EQ(p, q);
157}
158
160{
161 Polynomial p({1, 2, 3});
162 Polynomial copy(p);
163 Polynomial q(std::move(p));
164 EXPECT_EQ(q, copy);
165}
166
168{
169 Polynomial p({1, 2, 3});
170 Polynomial q;
171 q = p;
172 EXPECT_EQ(p, q);
173}
174
176{
177 Polynomial p({1, 2, 3});
178 Polynomial copy(p);
179 Polynomial q;
180 q = std::move(p);
181 EXPECT_EQ(q, copy);
182}
183
184// ===================================================================
185// Properties
186// ===================================================================
187
189{
190 Polynomial p({1, 2, 3}); // 1 + 2x + 3x^2
191 EXPECT_EQ(p.degree(), 2u);
192}
193
195{
196 Polynomial p(7.0);
197 EXPECT_EQ(p.degree(), 0u);
198}
199
201{
202 Polynomial p({1, 2, 5}); // 1 + 2x + 5x^2
203 EXPECT_DOUBLE_EQ(p.leading_coeff(), 5.0);
204}
205
211
213{
214 Polynomial p({-3, 0, 1}); // -3 + x^2
215 EXPECT_TRUE(p.is_monic());
216
217 Polynomial q({1, 2}); // 1 + 2x
218 EXPECT_FALSE(q.is_monic());
219}
220
222{
223 Polynomial p({1, 0, 3}); // 1 + 3x^2
224 EXPECT_TRUE(p.has_term(0));
225 EXPECT_FALSE(p.has_term(1));
226 EXPECT_TRUE(p.has_term(2));
227 EXPECT_FALSE(p.has_term(99));
228}
229
230// ===================================================================
231// Coefficient access
232// ===================================================================
233
235{
236 Polynomial p(3.0, 5); // 3x^5
237 EXPECT_DOUBLE_EQ(p[0], 0.0);
238 EXPECT_DOUBLE_EQ(p[5], 3.0);
239 EXPECT_DOUBLE_EQ(p[999], 0.0);
240}
241
242// ===================================================================
243// Evaluation
244// ===================================================================
245
247{
248 Polynomial p(5.0);
249 EXPECT_DOUBLE_EQ(p.eval(0.0), 5.0);
250 EXPECT_DOUBLE_EQ(p.eval(100.0), 5.0);
251 EXPECT_DOUBLE_EQ(p.eval(-3.14), 5.0);
252}
253
255{
256 Polynomial p({3, 2}); // 3 + 2x
257 EXPECT_DOUBLE_EQ(p.eval(0.0), 3.0);
258 EXPECT_DOUBLE_EQ(p.eval(5.0), 13.0);
259 EXPECT_DOUBLE_EQ(p.eval(-1.0), 1.0);
260}
261
263{
264 Polynomial p({-1, 0, 1}); // x^2 - 1
265 EXPECT_DOUBLE_EQ(p.eval(0.0), -1.0);
266 EXPECT_DOUBLE_EQ(p.eval(1.0), 0.0);
267 EXPECT_DOUBLE_EQ(p.eval(-1.0), 0.0);
268 EXPECT_DOUBLE_EQ(p.eval(3.0), 8.0);
269}
270
272{
273 Polynomial p;
274 EXPECT_DOUBLE_EQ(p.eval(42.0), 0.0);
275}
276
278{
279 Polynomial p({1, 1}); // 1 + x
280 EXPECT_DOUBLE_EQ(p(9.0), 10.0);
281}
282
284{
285 Polynomial p(1.0, 100); // x^100
286 EXPECT_DOUBLE_EQ(p.eval(1.0), 1.0);
287 EXPECT_DOUBLE_EQ(p.eval(0.0), 0.0);
288 EXPECT_DOUBLE_EQ(p.eval(-1.0), 1.0); // (-1)^100 = 1
289}
290
291// ===================================================================
292// Arithmetic
293// ===================================================================
294
296{
297 Polynomial p({1, 2, 3}); // 1 + 2x + 3x^2
298 Polynomial q({4, 5}); // 4 + 5x
299 Polynomial sum = p + q;
300 EXPECT_DOUBLE_EQ(sum[0], 5.0);
301 EXPECT_DOUBLE_EQ(sum[1], 7.0);
302 EXPECT_DOUBLE_EQ(sum[2], 3.0);
303}
304
306{
307 Polynomial p({1, 2});
308 Polynomial q({3, 4});
309 p += q;
310 EXPECT_DOUBLE_EQ(p[0], 4.0);
311 EXPECT_DOUBLE_EQ(p[1], 6.0);
312}
313
315{
316 Polynomial p({1, -2, 3});
317 p += p;
318 EXPECT_DOUBLE_EQ(p[0], 2.0);
319 EXPECT_DOUBLE_EQ(p[1], -4.0);
320 EXPECT_DOUBLE_EQ(p[2], 6.0);
321}
322
324{
325 Polynomial p({1, 2, 3});
326 Polynomial q = p + 4.0;
327 EXPECT_DOUBLE_EQ(q[0], 5.0);
328 EXPECT_DOUBLE_EQ(q[1], 2.0);
329 EXPECT_DOUBLE_EQ(q[2], 3.0);
330}
331
333{
334 Polynomial p({1, 2, 3});
335 Polynomial q = 4.0 + p;
336 EXPECT_DOUBLE_EQ(q[0], 5.0);
337 EXPECT_DOUBLE_EQ(q[1], 2.0);
338 EXPECT_DOUBLE_EQ(q[2], 3.0);
339}
340
342{
343 Polynomial p({5, 3});
344 Polynomial q({2, 1});
345 Polynomial diff = p - q;
346 EXPECT_DOUBLE_EQ(diff[0], 3.0);
347 EXPECT_DOUBLE_EQ(diff[1], 2.0);
348}
349
351{
352 Polynomial p({1, 2, 3});
353 Polynomial zero = p - p;
354 EXPECT_TRUE(zero.is_zero());
355}
356
358{
359 Polynomial p({1, 2, 3});
360 p -= p;
361 EXPECT_TRUE(p.is_zero());
362}
363
365{
366 Polynomial p({1, 2, 3});
367 Polynomial q = p - 4.0;
368 EXPECT_DOUBLE_EQ(q[0], -3.0);
369 EXPECT_DOUBLE_EQ(q[1], 2.0);
370 EXPECT_DOUBLE_EQ(q[2], 3.0);
371}
372
374{
375 Polynomial p({1, 2, 3});
376 Polynomial q = 4.0 - p;
377 EXPECT_DOUBLE_EQ(q[0], 3.0);
378 EXPECT_DOUBLE_EQ(q[1], -2.0);
379 EXPECT_DOUBLE_EQ(q[2], -3.0);
380}
381
383{
384 Polynomial p({1, -2, 3}); // 1 - 2x + 3x^2
385 Polynomial neg = -p;
386 EXPECT_DOUBLE_EQ(neg[0], -1.0);
387 EXPECT_DOUBLE_EQ(neg[1], 2.0);
388 EXPECT_DOUBLE_EQ(neg[2], -3.0);
389}
390
392{
393 Polynomial p({1, 1}); // (x + 1)
394 Polynomial q({-1, 1}); // (x - 1)
395 Polynomial prod = p * q;
396 // (x+1)(x-1) = x^2 - 1
397 EXPECT_DOUBLE_EQ(prod[0], -1.0);
398 EXPECT_DOUBLE_EQ(prod[1], 0.0);
399 EXPECT_DOUBLE_EQ(prod[2], 1.0);
400 EXPECT_EQ(prod.degree(), 2u);
401}
402
404{
405 Polynomial p({1, 2, 3});
406 Polynomial z;
407 Polynomial prod = p * z;
408 EXPECT_TRUE(prod.is_zero());
409}
410
412{
413 Polynomial p({1, 2, 3}); // 1 + 2x + 3x^2
414 Polynomial c(2.0);
415 Polynomial prod = p * c;
416 EXPECT_DOUBLE_EQ(prod[0], 2.0);
417 EXPECT_DOUBLE_EQ(prod[1], 4.0);
418 EXPECT_DOUBLE_EQ(prod[2], 6.0);
419}
420
422{
423 Polynomial p({1, 2, 3});
424 Polynomial q = p * 3.0;
425 EXPECT_DOUBLE_EQ(q[0], 3.0);
426 EXPECT_DOUBLE_EQ(q[1], 6.0);
427 EXPECT_DOUBLE_EQ(q[2], 9.0);
428
429 // Commutative form
430 Polynomial r = 3.0 * p;
431 EXPECT_EQ(q, r);
432}
433
435{
436 Polynomial p({2, 4, 6});
437 Polynomial q = p / 2.0;
438 EXPECT_DOUBLE_EQ(q[0], 1.0);
439 EXPECT_DOUBLE_EQ(q[1], 2.0);
440 EXPECT_DOUBLE_EQ(q[2], 3.0);
441}
442
444{
445 Polynomial p({1, 2});
446 EXPECT_THROW(p / 0.0, std::domain_error);
447}
448
449// ===================================================================
450// Polynomial division
451// ===================================================================
452
454{
455 // (x^2 - 1) / (x - 1) = (x + 1) with remainder 0
456 Polynomial p({-1, 0, 1}); // x^2 - 1
457 Polynomial d({-1, 1}); // x - 1
458 auto [q, r] = p.divmod(d);
459
460 EXPECT_DOUBLE_EQ(q[0], 1.0);
461 EXPECT_DOUBLE_EQ(q[1], 1.0);
462 EXPECT_EQ(q.degree(), 1u);
463 EXPECT_TRUE(r.is_zero());
464}
465
467{
468 // (x^3 + x + 1) / (x + 1)
469 Polynomial p({1, 1, 0, 1}); // 1 + x + x^3
470 Polynomial d({1, 1}); // 1 + x
471 auto [q, r] = p.divmod(d);
472
473 // Verify: p == q * d + r
474 Polynomial reconstructed = q * d + r;
476}
477
479{
480 Polynomial p({1, 2}); // 1 + 2x (degree 1)
481 Polynomial d({1, 0, 1}); // 1 + x^2 (degree 2)
482 auto [q, r] = p.divmod(d);
483 EXPECT_TRUE(q.is_zero());
484 EXPECT_EQ(r, p);
485}
486
488{
489 Polynomial p({1, 2});
490 Polynomial z;
491 EXPECT_THROW(p.divmod(z), std::domain_error);
492}
493
495{
496 // For several polynomial pairs, verify a == (a/b)*b + (a%b)
497 Polynomial a({3, -2, 0, 5, 1}); // 3 - 2x + 5x^3 + x^4
498 Polynomial b({1, 1, 1}); // 1 + x + x^2
499
500 Polynomial q = a / b;
501 Polynomial r = a % b;
502 EXPECT_EQ(a, q * b + r);
503}
504
506{
507 Polynomial a({-1, 0, 1}); // x^2 - 1
508 Polynomial b({-1, 1}); // x - 1
509
510 Polynomial q = a / b;
511 Polynomial r = a % b;
512 EXPECT_DOUBLE_EQ(q[0], 1.0);
513 EXPECT_DOUBLE_EQ(q[1], 1.0);
514 EXPECT_TRUE(r.is_zero());
515}
516
518{
519 std::mt19937 rng(0xA13F2026u);
520 std::uniform_int_distribution<int> scalar_dist(-3, 3);
521 std::uniform_int_distribution<int> x_dist(-2, 2);
522
523 for (size_t i = 0; i < 100; ++i)
524 {
526 Polynomial b = make_random_polynomial(rng, 3, -2, 2, true);
528 const double scalar = static_cast<double>(scalar_dist(rng));
529 const double x = static_cast<double>(x_dist(rng));
530
531 EXPECT_EQ(a * (b + c), a * b + a * c);
532 EXPECT_EQ((a + b) + c, a + (b + c));
533 EXPECT_EQ(scalar * a, a * scalar);
534
535 auto [q, r] = a.divmod(b);
536 EXPECT_EQ(q, a / b);
537 EXPECT_EQ(r, a % b);
538 EXPECT_EQ(a, q * b + r);
539 EXPECT_TRUE(r.is_zero() or r.degree() < b.degree());
540
541 Polynomial sum = a + b;
542 Polynomial diff = sum - b;
543 EXPECT_EQ(sum[0], a[0] + b[0]);
544 EXPECT_EQ(diff, a);
545 EXPECT_TRUE((a - a).is_zero());
546 EXPECT_TRUE(sum.is_zero() or sum[sum.degree()] != 0.0);
547
549 EXPECT_TRUE(std::abs(composed.eval(x) - a.eval(c.eval(x))) <= 1e-9);
550
551 Polynomial zero;
552 EXPECT_THROW(a.divmod(zero), std::domain_error);
553 }
554}
555
556// ===================================================================
557// Calculus
558// ===================================================================
559
565
567{
568 Polynomial p({3, 5}); // 3 + 5x
569 Polynomial dp = p.derivative();
570 EXPECT_EQ(dp.degree(), 0u);
571 EXPECT_DOUBLE_EQ(dp[0], 5.0);
572}
573
575{
576 Polynomial p({1, 2, 3}); // 1 + 2x + 3x^2
577 Polynomial dp = p.derivative();
578 // dp = 2 + 6x
579 EXPECT_DOUBLE_EQ(dp[0], 2.0);
580 EXPECT_DOUBLE_EQ(dp[1], 6.0);
581 EXPECT_EQ(dp.degree(), 1u);
582}
583
589
591{
592 Polynomial p({2, 6}); // 2 + 6x
593 Polynomial ip = p.integral();
594 // integral = 2x + 3x^2 (+ 0)
595 EXPECT_DOUBLE_EQ(ip[0], 0.0);
596 EXPECT_DOUBLE_EQ(ip[1], 2.0);
597 EXPECT_DOUBLE_EQ(ip[2], 3.0);
598}
599
601{
602 Polynomial p({2, 6}); // 2 + 6x
603 Polynomial ip = p.integral(5.0);
604 // integral = 5 + 2x + 3x^2
605 EXPECT_DOUBLE_EQ(ip[0], 5.0);
606 EXPECT_DOUBLE_EQ(ip[1], 2.0);
607 EXPECT_DOUBLE_EQ(ip[2], 3.0);
608}
609
611{
612 Polynomial p({3, -1, 4, 0, 2}); // 3 - x + 4x^2 + 2x^4
614 // integral -> derivative should recover p (constant lost, then regained as 0)
615 EXPECT_EQ(q, p);
616}
617
619{
620 Polynomial p({1, 0, 0, 6}); // 1 + 6x^3
621 Polynomial d3 = p.nth_derivative(3);
622 // 3rd derivative of 6x^3 = 36
623 EXPECT_DOUBLE_EQ(d3[0], 36.0);
624 EXPECT_EQ(d3.degree(), 0u);
625}
626
627// ===================================================================
628// Composition and power
629// ===================================================================
630
632{
633 Polynomial p({1, 0, 1}); // x^2 + 1
634 Polynomial q({1, 2}); // 2x + 1
635 // p(q(x)) = (2x+1)^2 + 1 = 4x^2 + 4x + 2
636 Polynomial comp = p.compose(q);
637 EXPECT_DOUBLE_EQ(comp[0], 2.0);
638 EXPECT_DOUBLE_EQ(comp[1], 4.0);
639 EXPECT_DOUBLE_EQ(comp[2], 4.0);
640}
641
643{
644 Polynomial p({1, 2, 3});
645 Polynomial id({0, 1}); // x
646 EXPECT_EQ(p.compose(id), p);
647}
648
650{
651 Polynomial p({1, 1}); // x + 1
652 Polynomial one = p.pow(0);
653 EXPECT_EQ(one.degree(), 0u);
654 EXPECT_DOUBLE_EQ(one[0], 1.0);
655}
656
658{
659 Polynomial p({1, 2, 3});
660 EXPECT_EQ(p.pow(1), p);
661}
662
664{
665 Polynomial p({1, 1}); // x + 1
666 Polynomial sq = p.pow(2);
667 // (x+1)^2 = x^2 + 2x + 1
668 EXPECT_DOUBLE_EQ(sq[0], 1.0);
669 EXPECT_DOUBLE_EQ(sq[1], 2.0);
670 EXPECT_DOUBLE_EQ(sq[2], 1.0);
671}
672
674{
675 Polynomial p({1, 1}); // x + 1
676 Polynomial cu = p.pow(3);
677 // (x+1)^3 = x^3 + 3x^2 + 3x + 1
678 EXPECT_DOUBLE_EQ(cu[0], 1.0);
679 EXPECT_DOUBLE_EQ(cu[1], 3.0);
680 EXPECT_DOUBLE_EQ(cu[2], 3.0);
681 EXPECT_DOUBLE_EQ(cu[3], 1.0);
682}
683
684// ===================================================================
685// GCD
686// ===================================================================
687
689{
690 // gcd(x^2 - 1, x - 1) = x - 1 (monic)
691 Polynomial a({-1, 0, 1}); // x^2 - 1
692 Polynomial b({-1, 1}); // x - 1
693 Polynomial g = Polynomial::gcd(a, b);
694
695 // g should be monic of degree 1
696 EXPECT_EQ(g.degree(), 1u);
697 EXPECT_DOUBLE_EQ(g.leading_coeff(), 1.0);
698 // g should divide both a and b
699 EXPECT_TRUE((a % g).is_zero());
700 EXPECT_TRUE((b % g).is_zero());
701}
702
704{
705 Polynomial a({0, 0, 1}); // x^2
706 Polynomial b({1, 1}); // x + 1
707 Polynomial g = Polynomial::gcd(a, b);
708 // Coprime: gcd should be constant (monic → 1)
709 EXPECT_TRUE(g.is_constant());
710 EXPECT_NEAR(g[0], 1.0, 1e-6);
711}
712
713// ===================================================================
714// Comparison
715// ===================================================================
716
718{
719 Polynomial p({1, 2, 3});
720 Polynomial q({1, 2, 3});
721 EXPECT_EQ(p, q);
722}
723
725{
726 Polynomial p({1, 2, 3});
727 Polynomial q({1, 2, 4});
728 EXPECT_NE(p, q);
729}
730
737
739{
740 // Same polynomial built differently
741 Polynomial p({1, 0, 3}); // 1 + 3x^2
743 terms.append({0, 1.0});
744 terms.append({2, 3.0});
745 Polynomial q(terms);
746 EXPECT_EQ(p, q);
747}
748
749// ===================================================================
750// Factory methods
751// ===================================================================
752
754{
755 // Single root at 2: (x - 2)
756 DynList<double> roots = {2.0};
758 EXPECT_DOUBLE_EQ(p.eval(2.0), 0.0);
759 EXPECT_EQ(p.degree(), 1u);
760}
761
763{
764 // Roots at 1 and -1: (x-1)(x+1) = x^2 - 1
765 DynList<double> roots = {1.0, -1.0};
767 EXPECT_NEAR(p.eval(1.0), 0.0, 1e-9);
768 EXPECT_NEAR(p.eval(-1.0), 0.0, 1e-9);
769 EXPECT_DOUBLE_EQ(p[2], 1.0);
770 EXPECT_NEAR(p[0], -1.0, 1e-9);
771}
772
774{
776 EXPECT_EQ(p.degree(), 3u);
777 EXPECT_DOUBLE_EQ(p[3], 1.0);
778 EXPECT_DOUBLE_EQ(p[0], 0.0);
779}
780
787
788// ===================================================================
789// Interpolation
790// ===================================================================
791
793{
794 // Line through (0, 1) and (1, 3): y = 2x + 1
796 pts.append(std::make_pair(0.0, 1.0));
797 pts.append(std::make_pair(1.0, 3.0));
798
800 EXPECT_NEAR(p(0.0), 1.0, 1e-9);
801 EXPECT_NEAR(p(1.0), 3.0, 1e-9);
802 EXPECT_NEAR(p[0], 1.0, 1e-9);
803 EXPECT_NEAR(p[1], 2.0, 1e-9);
804}
805
807{
808 // Points from y = x^2: (0,0), (1,1), (2,4)
810 pts.append(std::make_pair(0.0, 0.0));
811 pts.append(std::make_pair(1.0, 1.0));
812 pts.append(std::make_pair(2.0, 4.0));
813
815 EXPECT_NEAR(p(0.0), 0.0, 1e-9);
816 EXPECT_NEAR(p(1.0), 1.0, 1e-9);
817 EXPECT_NEAR(p(2.0), 4.0, 1e-9);
818 // Should recover x^2
819 EXPECT_NEAR(p[2], 1.0, 1e-9);
820 EXPECT_NEAR(p(3.0), 9.0, 1e-7);
821}
822
828
830{
832 pts.append(std::make_pair(1.0, 2.0));
833 pts.append(std::make_pair(1.0, 5.0));
834 EXPECT_THROW(Polynomial::interpolate(pts), std::domain_error);
835}
836
837// ===================================================================
838// Iteration
839// ===================================================================
840
842{
843 Polynomial p({1, 0, 3}); // 1 + 3x^2
844 size_t count = 0;
845 p.for_each_term([&count](size_t exp, const double & c)
846 {
847 if (exp == 0)
848 EXPECT_DOUBLE_EQ(c, 1.0);
849 else if (exp == 2)
850 EXPECT_DOUBLE_EQ(c, 3.0);
851 else
852 FAIL() << "unexpected exponent " << exp;
853 ++count;
854 });
855 EXPECT_EQ(count, 2u);
856}
857
859{
860 Polynomial p({1, 0, 3});
861 auto tl = p.terms_list();
862 EXPECT_EQ(tl.size(), 2u);
863}
864
866{
867 Polynomial p({1, 0, 3});
868 auto exps = p.exponents();
869 EXPECT_EQ(exps.size(), 2u);
870}
871
873{
874 Polynomial p({1, 0, 3});
875 auto coeffs = p.coefficients();
876 ASSERT_EQ(coeffs.size(), 2u);
877 EXPECT_DOUBLE_EQ(coeffs[0], 1.0);
878 EXPECT_DOUBLE_EQ(coeffs[1], 3.0);
879}
880
881// ===================================================================
882// String representation
883// ===================================================================
884
886{
887 Polynomial p;
888 EXPECT_EQ(p.to_str(), "0");
889}
890
892{
893 Polynomial p(5.0);
894 EXPECT_EQ(p.to_str(), "5");
895}
896
898{
899 Polynomial p({3, 2}); // 3 + 2x
900 std::string s = p.to_str();
901 // Should contain "2x" and "3"
902 EXPECT_NE(s.find("2x"), std::string::npos);
903 EXPECT_NE(s.find("3"), std::string::npos);
904}
905
907{
908 Polynomial p({1, 2, 3});
909 std::ostringstream oss;
910 oss << p;
911 EXPECT_FALSE(oss.str().empty());
912 EXPECT_NE(oss.str(), "0");
913}
914
915// ===================================================================
916// Edge cases
917// ===================================================================
918
920{
921 Polynomial p({1, 2, 3});
922 Polynomial q = p - p;
923 EXPECT_TRUE(q.is_zero());
924}
925
927{
928 // x^1000 + 1
930 terms.append({0, 1.0});
931 terms.append({1000, 1.0});
932 Polynomial p(terms);
933
934 EXPECT_EQ(p.degree(), 1000u);
935 EXPECT_EQ(p.num_terms(), 2u);
936 EXPECT_DOUBLE_EQ(p.eval(1.0), 2.0);
937 EXPECT_DOUBLE_EQ(p.eval(0.0), 1.0);
938
939 // Functional correctness checks (timing moved to benchmark suite)
940 const double value = p.eval(1.5);
941 EXPECT_GT(value, 1.0);
942
943 Polynomial squared = p * p;
944 EXPECT_EQ(squared.degree(), 2000u);
945 EXPECT_EQ(squared.num_terms(), 3u);
946
947 auto [quotient, remainder] = squared.divmod(p);
949 EXPECT_TRUE(remainder.is_zero());
950
951 Polynomial linear({0, 2}); // 2x
953 EXPECT_EQ(composed.degree(), 1000u);
954 EXPECT_EQ(composed.num_terms(), 2u);
955}
956
958{
959 Polynomial p({1, 1}); // x + 1
960 Polynomial sq = p * p;
961 EXPECT_EQ(sq, p.pow(2));
962}
963
965{
966 Polynomial p({1, 2, 3});
967 Polynomial doubled = p + p;
968 EXPECT_EQ(doubled, p * 2.0);
969}
970
972{
973 Gen_Polynomial<int> p({1, 2, 3});
974 Gen_Polynomial<int> q({4, 5});
975 auto sum = p + q;
976 EXPECT_EQ(sum[0], 5);
977 EXPECT_EQ(sum[1], 7);
978 EXPECT_EQ(sum[2], 3);
979}
980
982{
983 Gen_Polynomial<int> p({1, 1}); // x + 1
984 Gen_Polynomial<int> q({-1, 1}); // x - 1
985 auto prod = p * q;
986 // x^2 - 1
987 EXPECT_EQ(prod[0], -1);
988 EXPECT_EQ(prod[1], 0);
989 EXPECT_EQ(prod[2], 1);
990}
991
993{
994 Gen_Polynomial<int> a({-1, 0, 1}); // x^2 - 1
995 Gen_Polynomial<int> b({-1, 1}); // x - 1
996 auto [q, r] = a.divmod(b);
997 EXPECT_EQ(q[0], 1);
998 EXPECT_EQ(q[1], 1);
999 EXPECT_TRUE(r.is_zero());
1000}
1001
1003{
1004 // p(x) = x^3, p'(x) = 3x^2, p'(2) = 12
1005 Polynomial p(1.0, 3);
1006 Polynomial dp = p.derivative();
1007 EXPECT_DOUBLE_EQ(dp.eval(2.0), 12.0);
1008}
1009
1011{
1012 Polynomial p({1, 2, 3}); // 1 + 2x + 3x^2
1013 Polynomial c(5.0);
1014 // p(5) = 1 + 10 + 75 = 86
1015 Polynomial comp = p.compose(c);
1016 EXPECT_TRUE(comp.is_constant());
1017 EXPECT_DOUBLE_EQ(comp[0], 86.0);
1018}
1019
1021{
1022 // Roots at 1, 2, 3
1023 DynList<double> roots = {1.0, 2.0, 3.0};
1025 EXPECT_EQ(p.degree(), 3u);
1026 EXPECT_NEAR(p(1.0), 0.0, 1e-9);
1027 EXPECT_NEAR(p(2.0), 0.0, 1e-9);
1028 EXPECT_NEAR(p(3.0), 0.0, 1e-9);
1029 // p(0) = (-1)(-2)(-3) = -6
1030 EXPECT_NEAR(p(0.0), -6.0, 1e-9);
1031}
1032
1033// ===================================================================
1034// Horner evaluation
1035// ===================================================================
1036
1038{
1039 // p(x) = 2 + 3x + x^2, p(3) = 2 + 9 + 9 = 20
1040 Polynomial p({2, 3, 1});
1041 EXPECT_DOUBLE_EQ(p.horner_eval(3.0), 20.0);
1042 EXPECT_DOUBLE_EQ(p.horner_eval(0.0), 2.0);
1043 EXPECT_DOUBLE_EQ(p.horner_eval(1.0), 6.0);
1044}
1045
1047{
1048 // Compare horner_eval and sparse_eval on a polynomial
1049 Polynomial p({-1, 0, 0, 1}); // x^3 - 1
1050 for (double x = -2.0; x <= 3.0; x += 0.5)
1051 EXPECT_NEAR(p.horner_eval(x), p.sparse_eval(x), 1e-12);
1052}
1053
1055{
1056 // Dense polynomial — should use Horner internally
1057 Polynomial dense({1, 2, 3, 4, 5});
1058 EXPECT_DOUBLE_EQ(dense(1.0), 15.0);
1059
1060 // Sparse polynomial — should use sparse path
1061 Polynomial sparse(1.0, 100); // x^100
1062 EXPECT_DOUBLE_EQ(sparse(1.0), 1.0);
1063 EXPECT_DOUBLE_EQ(sparse(0.0), 0.0);
1064}
1065
1071
1072// ===================================================================
1073// Multi-point evaluation
1074// ===================================================================
1075
1077{
1078 Polynomial p({0, 0, 1}); // x^2
1079 DynList<double> points = {0.0, 1.0, 2.0, 3.0, -1.0};
1080 DynList<double> results = p.multi_eval(points);
1081
1082 DynList<double> expected = {0.0, 1.0, 4.0, 9.0, 1.0};
1083 auto it_r = results.get_it();
1084 auto it_e = expected.get_it();
1085 while (it_r.has_curr())
1086 {
1087 EXPECT_NEAR(it_r.get_curr(), it_e.get_curr(), 1e-12);
1088 it_r.next_ne();
1089 it_e.next_ne();
1090 }
1091}
1092
1094{
1095 Polynomial p({1, 2});
1096 DynList<double> empty;
1097 DynList<double> results = p.multi_eval(empty);
1098 EXPECT_TRUE(results.is_empty());
1099}
1100
1101// ===================================================================
1102// Definite integral
1103// ===================================================================
1104
1106{
1107 // integral of 2x+1 from 0 to 3 = [x^2+x]_0^3 = 12
1108 Polynomial p({1, 2});
1109 EXPECT_NEAR(p.definite_integral(0.0, 3.0), 12.0, 1e-12);
1110}
1111
1113{
1114 // integral of x^2 from 0 to 1 = 1/3
1115 Polynomial p({0, 0, 1});
1116 EXPECT_NEAR(p.definite_integral(0.0, 1.0), 1.0/3.0, 1e-12);
1117}
1118
1120{
1121 // integral of x^3 from -1 to 1 = 0 (odd function)
1122 Polynomial p({0, 0, 0, 1});
1123 EXPECT_NEAR(p.definite_integral(-1.0, 1.0), 0.0, 1e-12);
1124}
1125
1126// ===================================================================
1127// Extended GCD
1128// ===================================================================
1129
1131{
1132 // a = x^2 - 1, b = x - 1, gcd = x - 1
1133 Polynomial a({-1, 0, 1});
1134 Polynomial b({-1, 1});
1135 auto [g, s, t] = Polynomial::xgcd(a, b);
1136
1137 // g should be monic and divide both a and b
1138 EXPECT_EQ(g.degree(), 1u);
1139 EXPECT_TRUE(g.is_monic());
1140 EXPECT_NEAR(g[0], -1.0, 1e-9);
1141 EXPECT_NEAR(g[1], 1.0, 1e-9);
1142
1143 // Verify Bezout identity: s*a + t*b = g
1144 Polynomial bezout = s * a + t * b;
1145 EXPECT_EQ(bezout.degree(), g.degree());
1146 EXPECT_NEAR(bezout[0], g[0], 1e-9);
1147 EXPECT_NEAR(bezout[1], g[1], 1e-9);
1148}
1149
1151{
1152 // x^2 + 1 and x - 1 are coprime
1153 Polynomial a({1, 0, 1});
1154 Polynomial b({-1, 1});
1155 auto [g, s, t] = Polynomial::xgcd(a, b);
1156
1157 EXPECT_EQ(g.degree(), 0u);
1158 EXPECT_NEAR(g[0], 1.0, 1e-9);
1159
1160 // Verify s*a + t*b = 1
1161 Polynomial bezout = s * a + t * b;
1162 EXPECT_TRUE(bezout.is_constant());
1163 EXPECT_NEAR(bezout[0], 1.0, 1e-9);
1164}
1165
1166// ===================================================================
1167// LCM
1168// ===================================================================
1169
1171{
1172 // a = (x-1)(x-2), b = (x-2)(x-3)
1173 // gcd = (x-2), lcm = (x-1)(x-2)(x-3)
1177
1178 EXPECT_EQ(l.degree(), 3u);
1179 EXPECT_NEAR(l(1.0), 0.0, 1e-8);
1180 EXPECT_NEAR(l(2.0), 0.0, 1e-8);
1181 EXPECT_NEAR(l(3.0), 0.0, 1e-8);
1182}
1183
1185{
1186 Polynomial a({1, 2});
1187 Polynomial z;
1188 EXPECT_TRUE(Polynomial::lcm(a, z).is_zero());
1189 EXPECT_TRUE(Polynomial::lcm(z, a).is_zero());
1190}
1191
1192// ===================================================================
1193// Pseudo-division
1194// ===================================================================
1195
1197{
1198 // a = 3x^3 + x + 2, b = x^2 + 1 (integer-like)
1199 Gen_Polynomial<int> a({2, 1, 0, 3});
1200 Gen_Polynomial<int> b({1, 0, 1});
1201
1202 auto [q, r] = a.pseudo_divmod(b);
1203
1204 // Verify: lc(b)^(deg(a)-deg(b)+1) * a = q*b + r
1205 int lc_b = b.leading_coeff();
1206 size_t delta = a.degree() - b.degree() + 1;
1207 int scale = 1;
1208 for (size_t i = 0; i < delta; ++i)
1209 scale *= lc_b;
1210
1212 Gen_Polynomial<int> rhs = q * b + r;
1213 EXPECT_EQ(lhs, rhs);
1214}
1215
1217{
1218 Gen_Polynomial<int> a({1, 2, 3});
1220 EXPECT_THROW(a.pseudo_divmod(z), std::domain_error);
1221}
1222
1223// ===================================================================
1224// Algebraic transformations
1225// ===================================================================
1226
1228{
1229 Polynomial p({2, 4, 6}); // 6x^2 + 4x + 2
1230 Polynomial m = p.to_monic();
1231 EXPECT_TRUE(m.is_monic());
1232 EXPECT_NEAR(m[2], 1.0, 1e-12);
1233 EXPECT_NEAR(m[1], 4.0/6.0, 1e-12);
1234 EXPECT_NEAR(m[0], 2.0/6.0, 1e-12);
1235}
1236
1238{
1239 Polynomial p;
1240 EXPECT_THROW(p.to_monic(), std::domain_error);
1241}
1242
1244{
1245 // p(x) = 1 + 2x + 3x^2, reverse = 3 + 2x + x^2
1246 Polynomial p({1, 2, 3});
1247 Polynomial rev = p.reverse();
1248 EXPECT_NEAR(rev[0], 3.0, 1e-12);
1249 EXPECT_NEAR(rev[1], 2.0, 1e-12);
1250 EXPECT_NEAR(rev[2], 1.0, 1e-12);
1251}
1252
1254{
1255 EXPECT_TRUE(Polynomial().reverse().is_zero());
1256}
1257
1259{
1260 // Palindromic: 1 + 3x + 3x^2 + x^3
1261 Polynomial p({1, 3, 3, 1});
1262 EXPECT_EQ(p, p.reverse());
1263}
1264
1266{
1267 // p(x) = 1 + 2x + 3x^2, p(-x) = 1 - 2x + 3x^2
1268 Polynomial p({1, 2, 3});
1270 EXPECT_NEAR(neg[0], 1.0, 1e-12);
1271 EXPECT_NEAR(neg[1], -2.0, 1e-12);
1272 EXPECT_NEAR(neg[2], 3.0, 1e-12);
1273}
1274
1276{
1277 // p(-x) evaluated at x should equal p evaluated at -x
1278 Polynomial p({-1, 3, 0, -2, 1});
1280 for (double x = -3.0; x <= 3.0; x += 0.7)
1281 EXPECT_NEAR(neg(x), p(-x), 1e-10);
1282}
1283
1285{
1286 // p(x) = x^2, shift by 1 => p(x+1) = (x+1)^2 = x^2 + 2x + 1
1287 Polynomial p({0, 0, 1});
1288 Polynomial shifted = p.shift(1.0);
1289 EXPECT_NEAR(shifted[0], 1.0, 1e-12);
1290 EXPECT_NEAR(shifted[1], 2.0, 1e-12);
1291 EXPECT_NEAR(shifted[2], 1.0, 1e-12);
1292}
1293
1295{
1296 Polynomial p({1, -2, 3});
1297 double k = 2.5;
1299 for (double x = -3.0; x <= 3.0; x += 0.7)
1300 EXPECT_NEAR(shifted(x), p(x + k), 1e-9);
1301}
1302
1304{
1305 // p(x) = 1 + 2x, shift_up(2) => x^2 + 2x^3
1306 Polynomial p({1, 2});
1307 Polynomial up = p.shift_up(2);
1308 EXPECT_EQ(up.degree(), 3u);
1309 EXPECT_NEAR(up[0], 0.0, 1e-12);
1310 EXPECT_NEAR(up[1], 0.0, 1e-12);
1311 EXPECT_NEAR(up[2], 1.0, 1e-12);
1312 EXPECT_NEAR(up[3], 2.0, 1e-12);
1313}
1314
1316{
1317 // p(x) = x^2 + 2x^3, shift_down(2) => 1 + 2x
1318 Polynomial p({0, 0, 1, 2});
1319 Polynomial down = p.shift_down(2);
1320 EXPECT_EQ(down.degree(), 1u);
1321 EXPECT_NEAR(down[0], 1.0, 1e-12);
1322 EXPECT_NEAR(down[1], 2.0, 1e-12);
1323}
1324
1326{
1327 // p(x) = 1 + x + x^2 + x^3, shift_down(2) => 1 + x
1328 Polynomial p({1, 1, 1, 1});
1329 Polynomial down = p.shift_down(2);
1330 EXPECT_EQ(down.degree(), 1u);
1331 EXPECT_NEAR(down[0], 1.0, 1e-12);
1332 EXPECT_NEAR(down[1], 1.0, 1e-12);
1333}
1334
1336{
1337 // p(x) = 1 + 2x + 3x^2 + 4x^3, truncate(2) => 1 + 2x
1338 Polynomial p({1, 2, 3, 4});
1339 Polynomial t = p.truncate(2);
1340 EXPECT_EQ(t.degree(), 1u);
1341 EXPECT_NEAR(t[0], 1.0, 1e-12);
1342 EXPECT_NEAR(t[1], 2.0, 1e-12);
1343}
1344
1346{
1347 Polynomial p({1, 2, 3});
1348 Polynomial t = p.truncate(100);
1349 EXPECT_EQ(t, p);
1350}
1351
1353{
1354 // p(x) = 1 + 3x^2 (sparse: no x^1 term)
1355 Polynomial p({1, 0, 3});
1356 Array<double> dense = p.to_dense();
1357 ASSERT_EQ(dense.size(), 3u);
1358 EXPECT_DOUBLE_EQ(dense(0), 1.0);
1359 EXPECT_DOUBLE_EQ(dense(1), 0.0);
1360 EXPECT_DOUBLE_EQ(dense(2), 3.0);
1361}
1362
1364{
1365 Polynomial p;
1367 EXPECT_EQ(dense.size(), 0u);
1368}
1369
1371{
1372 // x^5 + 1: should have 6 elements
1374 terms.append(std::make_pair(size_t(0), 1.0));
1375 terms.append(std::make_pair(size_t(5), 1.0));
1376 Polynomial p(terms);
1378 ASSERT_EQ(dense.size(), 6u);
1379 EXPECT_DOUBLE_EQ(dense(0), 1.0);
1380 EXPECT_DOUBLE_EQ(dense(1), 0.0);
1381 EXPECT_DOUBLE_EQ(dense(2), 0.0);
1382 EXPECT_DOUBLE_EQ(dense(3), 0.0);
1383 EXPECT_DOUBLE_EQ(dense(4), 0.0);
1384 EXPECT_DOUBLE_EQ(dense(5), 1.0);
1385}
1386
1387// ===================================================================
1388// Square-free
1389// ===================================================================
1390
1392{
1393 // (x-1)^2 * (x-2) = x^3 - 4x^2 + 5x - 2
1394 // square-free part = (x-1)(x-2) = x^2 - 3x + 2
1396 Polynomial p = factor * factor * Polynomial::from_roots(DynList<double>({2.0}));
1397
1399 EXPECT_EQ(sf.degree(), 2u);
1400 EXPECT_NEAR(sf(1.0), 0.0, 1e-8);
1401 EXPECT_NEAR(sf(2.0), 0.0, 1e-8);
1402}
1403
1405{
1408 // Should have same roots, same degree
1409 EXPECT_EQ(sf.degree(), 3u);
1410 EXPECT_NEAR(sf(1.0), 0.0, 1e-8);
1411 EXPECT_NEAR(sf(2.0), 0.0, 1e-8);
1412 EXPECT_NEAR(sf(3.0), 0.0, 1e-8);
1413}
1414
1415// ===================================================================
1416// Cauchy bound
1417// ===================================================================
1418
1420{
1421 // p(x) = (x-1)(x-2)(x-3) = x^3 - 6x^2 + 11x - 6
1422 // All roots are |r| <= 3. Cauchy bound should be >= 3.
1424 double bound = p.cauchy_bound();
1425 EXPECT_GE(bound, 3.0);
1426}
1427
1433
1435{
1436 Polynomial p;
1437 EXPECT_THROW(p.cauchy_bound(), std::domain_error);
1438}
1439
1441{
1443 p.set_coeff(0, 1);
1444 p.set_coeff(1, 3);
1445 p.set_coeff(2, 2);
1446 EXPECT_EQ(p.cauchy_bound(), 3);
1447}
1448
1449// ===================================================================
1450// Descartes sign variations
1451// ===================================================================
1452
1454{
1455 // p(x) = x^2 - 3x + 2 = (x-1)(x-2). Coefficients: 2, -3, 1
1456 // Sign changes: + -> - -> + = 2 changes.
1457 // Descartes: at most 2 positive roots (and exactly 2).
1458 Polynomial p({2, -3, 1});
1459 EXPECT_EQ(p.sign_variations(), 2u);
1460}
1461
1463{
1464 // p(x) = 1 + x + x^2. All positive. No positive roots.
1465 Polynomial p({1, 1, 1});
1466 EXPECT_EQ(p.sign_variations(), 0u);
1467}
1468
1474
1475// ===================================================================
1476// Sturm chain and root counting
1477// ===================================================================
1478
1480{
1481 Polynomial p({-5, 1}); // x - 5
1482 auto chain = p.sturm_chain();
1483 EXPECT_EQ(chain.size(), 2u); // p, p'
1484}
1485
1487{
1488 // x^2 - 1 = (x-1)(x+1): 2 real roots
1489 Polynomial p({-1, 0, 1});
1490 EXPECT_EQ(p.count_real_roots(-10.0, 10.0), 2u);
1491 EXPECT_EQ(p.count_real_roots(0.0, 10.0), 1u);
1492 EXPECT_EQ(p.count_real_roots(2.0, 10.0), 0u);
1493}
1494
1496{
1497 // (x-1)(x-2)(x-3) has 3 real roots
1499 EXPECT_EQ(p.count_real_roots(-10.0, 10.0), 3u);
1500 EXPECT_EQ(p.count_real_roots(0.0, 1.5), 1u);
1501 EXPECT_EQ(p.count_real_roots(1.5, 2.5), 1u);
1502 EXPECT_EQ(p.count_real_roots(2.5, 10.0), 1u);
1503}
1504
1506{
1507 Polynomial p({-1, 0, 1}); // x^2 - 1
1508 EXPECT_EQ(p.count_real_roots(10.0, -10.0), 2u);
1509}
1510
1512{
1513 // x^4 - 5x^2 + 4 = (x-1)(x+1)(x-2)(x+2): 4 real roots
1514 Polynomial p({4, 0, -5, 0, 1});
1515 EXPECT_EQ(p.count_all_real_roots(), 4u);
1516}
1517
1519{
1520 Polynomial p;
1521 EXPECT_EQ(p.count_real_roots(-10.0, 10.0), 0u);
1522 EXPECT_EQ(p.count_real_roots(10.0, -10.0), 0u);
1524}
1525
1527{
1528 // x^2 + 1: no real roots
1529 Polynomial p({1, 0, 1});
1530 EXPECT_EQ(p.count_all_real_roots(), 0u);
1531}
1532
1533// ===================================================================
1534// Bisection root finding
1535// ===================================================================
1536
1538{
1539 // x - 3 = 0 => root at 3
1540 Polynomial p({-3, 1});
1541 double root = p.bisect_root(0.0, 10.0);
1542 EXPECT_NEAR(root, 3.0, 1e-10);
1543}
1544
1546{
1547 // x^2 - 2 => root at sqrt(2) ≈ 1.4142
1548 Polynomial p({-2, 0, 1});
1549 double root = p.bisect_root(1.0, 2.0);
1550 EXPECT_NEAR(root, std::sqrt(2.0), 1e-10);
1551}
1552
1554{
1555 Polynomial p({1, 0, 1}); // x^2 + 1, always positive
1556 EXPECT_THROW(p.bisect_root(1.0, 2.0), std::domain_error);
1557}
1558
1560{
1561 Polynomial p({-2, 1}); // x - 2
1562 EXPECT_NEAR(p.bisect_root(10.0, 0.0), 2.0, 1e-10);
1563}
1564
1565// ===================================================================
1566// Newton-Raphson root finding
1567// ===================================================================
1568
1570{
1571 Polynomial p({-5, 2}); // 2x - 5 => root at 2.5
1572 double root = p.newton_root(0.0);
1573 EXPECT_NEAR(root, 2.5, 1e-10);
1574}
1575
1577{
1578 // x^2 - 2 => root at sqrt(2)
1579 Polynomial p({-2, 0, 1});
1580 double root = p.newton_root(1.5);
1581 EXPECT_NEAR(root, std::sqrt(2.0), 1e-10);
1582}
1583
1585{
1586 // x^3 - 27 => root at 3
1587 Polynomial p({-27, 0, 0, 1});
1588 double root = p.newton_root(2.0);
1589 EXPECT_NEAR(root, 3.0, 1e-10);
1590}
1591
1593{
1594 // x^2 + 1 has derivative 2x which is zero at x=0, but f(0)=1 != 0
1595 Polynomial p({1, 0, 1});
1596 EXPECT_THROW(p.newton_root(0.0), std::domain_error);
1597}
1598
1599// ===================================================================
1600// Integration: shift_up / shift_down round-trip
1601// ===================================================================
1602
1609
1611{
1612 Polynomial p({1, 2, 3});
1613 EXPECT_EQ(p.shift_up(0), p);
1614}
1615
1616// ===================================================================
1617// Truncate + shift integration
1618// ===================================================================
1619
1621{
1622 // p(x) mod x^n: only lower terms survive
1623 Polynomial p({1, 2, 3, 4, 5});
1624 Polynomial t = p.truncate(3);
1625 // Check that t(x) = p(x) mod x^3
1626 EXPECT_NEAR(t[0], 1.0, 1e-12);
1627 EXPECT_NEAR(t[1], 2.0, 1e-12);
1628 EXPECT_NEAR(t[2], 3.0, 1e-12);
1629 EXPECT_FALSE(t.has_term(3));
1630 EXPECT_FALSE(t.has_term(4));
1631}
1632
1633// ===================================================================
1634// Layer 5 — Exact Univariate Factorization (Cantor-Zassenhaus)
1635// ===================================================================
1636
1637namespace {
1638
1640
1642{
1643 IntPoly product(1);
1644
1645 for (const auto &term : factors)
1646 {
1647 IntPoly block(1);
1648 for (size_t i = 0; i < term.multiplicity; ++i)
1649 block *= term.factor;
1650 product *= block;
1651 }
1652
1653 return product;
1654}
1655
1656bool congruent_mod(const IntPoly &a, const IntPoly &b, long long mod)
1657{
1658 const size_t max_degree = std::max(a.degree(), b.degree());
1659 for (size_t exp = 0; exp <= max_degree; ++exp)
1660 {
1661 long long diff = (a.get_coeff(exp) - b.get_coeff(exp)) % mod;
1662 if (diff < 0)
1663 diff += mod;
1664 if (diff != 0)
1665 return false;
1666 }
1667
1668 return true;
1669}
1670
1671} // namespace
1672
1673// --- Content Tests ---
1674
1676{
1677 // content(6x^2 + 4x + 2) = 2
1678 IntPoly p;
1679 p.set_coeff(0, 2);
1680 p.set_coeff(1, 4);
1681 p.set_coeff(2, 6);
1682 EXPECT_EQ(p.content(), 2);
1683}
1684
1686{
1687 // content(x^2 + 2x + 3) = 1 (gcd(3, 2, 1))
1688 IntPoly p;
1689 p.set_coeff(0, 3);
1690 p.set_coeff(1, 2);
1691 p.set_coeff(2, 1);
1692 EXPECT_EQ(p.content(), 1);
1693}
1694
1696{
1697 // content(-4x + 2) = -2 (negative leading coeff)
1698 IntPoly p;
1699 p.set_coeff(0, 2);
1700 p.set_coeff(1, -4);
1701 EXPECT_EQ(p.content(), -2);
1702}
1703
1705{
1706 IntPoly p;
1707 EXPECT_EQ(p.content(), 0);
1708}
1709
1710// --- Primitive Part Tests ---
1711
1713{
1714 // primitive_part(6x^2 + 4x + 2) = 3x^2 + 2x + 1
1715 IntPoly p;
1716 p.set_coeff(0, 2);
1717 p.set_coeff(1, 4);
1718 p.set_coeff(2, 6);
1719 auto prim = p.primitive_part();
1720 EXPECT_EQ(prim.get_coeff(0), 1);
1721 EXPECT_EQ(prim.get_coeff(1), 2);
1722 EXPECT_EQ(prim.get_coeff(2), 3);
1723}
1724
1726{
1727 // primitive_part(-4x + 2) → lead coeff positive
1728 IntPoly p;
1729 p.set_coeff(0, 2);
1730 p.set_coeff(1, -4);
1731 auto prim = p.primitive_part();
1732 EXPECT_GT(prim.leading_coeff(), 0);
1733}
1734
1736{
1737 IntPoly p;
1738 auto prim = p.primitive_part();
1739 EXPECT_TRUE(prim.is_zero());
1740}
1741
1742// --- Integer Exact Quotient Tests ---
1743
1745{
1746 IntPoly a;
1747 a.set_coeff(0, 1);
1748 a.set_coeff(1, 2);
1749
1750 IntPoly zero;
1751 EXPECT_THROW(IntPoly::_integer_exact_quot(a, zero), std::domain_error);
1752}
1753
1755{
1756 IntPoly a;
1757 a.set_coeff(0, 2);
1758 a.set_coeff(1, 4);
1759 a.set_coeff(2, 6);
1760
1762 EXPECT_EQ(q.get_coeff(0), 1);
1763 EXPECT_EQ(q.get_coeff(1), 2);
1764 EXPECT_EQ(q.get_coeff(2), 3);
1765}
1766
1768{
1769 IntPoly a;
1770 a.set_coeff(0, 1);
1771 a.set_coeff(1, 4);
1772
1773 EXPECT_THROW(IntPoly::_integer_exact_quot(a, IntPoly(2)), std::domain_error);
1774}
1775
1777{
1778 IntPoly a;
1779 a.set_coeff(0, 1);
1780 a.set_coeff(2, 1);
1781
1782 IntPoly b;
1783 b.set_coeff(0, 2);
1784 b.set_coeff(1, 1);
1785
1786 EXPECT_THROW(IntPoly::_integer_exact_quot(a, b), std::domain_error);
1787}
1788
1789// --- Integer GCD Tests ---
1790
1792{
1793 // gcd(x - 1, x - 1) = x - 1
1794 IntPoly a, b;
1795 a.set_coeff(0, -1);
1796 a.set_coeff(1, 1);
1797 b.set_coeff(0, -1);
1798 b.set_coeff(1, 1);
1799 auto g = IntPoly::integer_gcd(a, b);
1800 EXPECT_EQ(g.degree(), 1);
1801 EXPECT_TRUE(g.get_coeff(0) == -1 or g.get_coeff(0) == 1);
1802}
1803
1805{
1806 // gcd(x^2 - 1, x - 1) = x - 1
1807 IntPoly a, b;
1808 a.set_coeff(0, -1);
1809 a.set_coeff(2, 1);
1810 b.set_coeff(0, -1);
1811 b.set_coeff(1, 1);
1812 auto g = IntPoly::integer_gcd(a, b);
1813 EXPECT_EQ(g.degree(), 1);
1814}
1815
1817{
1818 // gcd(x + 1, x + 2) = 1 (coprime)
1819 IntPoly a, b;
1820 a.set_coeff(0, 1);
1821 a.set_coeff(1, 1);
1822 b.set_coeff(0, 2);
1823 b.set_coeff(1, 1);
1824 auto g = IntPoly::integer_gcd(a, b);
1825 EXPECT_TRUE(g.is_constant());
1826}
1827
1829{
1830 // gcd(x^3 - 1, x^2 - 1) = x - 1
1831 IntPoly a, b;
1832 a.set_coeff(0, -1);
1833 a.set_coeff(3, 1);
1834 b.set_coeff(0, -1);
1835 b.set_coeff(2, 1);
1836 auto g = IntPoly::integer_gcd(a, b);
1837 EXPECT_EQ(g.degree(), 1);
1838}
1839
1840// --- Yun SFD Tests ---
1841
1843{
1844 // x^2 + 2x + 1 = (x+1)^2, so SFD gives (x+1)^2
1845 IntPoly p;
1846 p.set_coeff(0, 1);
1847 p.set_coeff(1, 2);
1848 p.set_coeff(2, 1);
1849 auto sfd = p.yun_sfd();
1850 EXPECT_TRUE(sfd.size() >= 1);
1851 EXPECT_EQ(sfd.get_first().multiplicity, 2);
1852}
1853
1855{
1856 // (x^2 - 1)^2 = (x-1)^2(x+1)^2
1857 IntPoly f, p;
1858 f.set_coeff(0, -1);
1859 f.set_coeff(2, 1);
1860 p = f * f;
1861 auto sfd = p.yun_sfd();
1862 EXPECT_EQ(sfd.size(), 1);
1863 EXPECT_EQ(sfd.get_first().multiplicity, 2);
1864}
1865
1867{
1868 // x^3 - x = x(x-1)(x+1) (square-free)
1869 IntPoly p;
1870 p.set_coeff(0, 0);
1871 p.set_coeff(1, -1);
1872 p.set_coeff(3, 1);
1873 auto sfd = p.yun_sfd();
1874 // Should be square-free or show multiplicity 1
1875 for (auto &term : sfd)
1876 EXPECT_EQ(term.multiplicity, 1);
1877}
1878
1880{
1881 // (x^2 - 1)^3 (repeated degree 2)
1882 IntPoly f, p;
1883 f.set_coeff(0, -1);
1884 f.set_coeff(2, 1);
1885 p = f * f * f;
1886 auto sfd = p.yun_sfd();
1887 EXPECT_EQ(sfd.get_first().multiplicity, 3);
1888}
1889
1891{
1892 // Constant polynomial
1893 IntPoly p(5);
1894 auto sfd = p.yun_sfd();
1895 EXPECT_TRUE(sfd.is_empty());
1896}
1897
1898// --- Factor Mod P Tests ---
1899
1901{
1902 // x - 2 over F_7 is irreducible
1903 IntPoly p;
1904 p.set_coeff(0, -2);
1905 p.set_coeff(1, 1);
1906 auto factors = IntPoly::factor_mod_p(p, 7);
1907 EXPECT_EQ(factors.size(), 1);
1908}
1909
1911{
1912 // x^2 - 1 = (x-1)(x+1) over any odd prime
1913 IntPoly p;
1914 p.set_coeff(0, -1);
1915 p.set_coeff(2, 1);
1916 auto factors = IntPoly::factor_mod_p(p, 5);
1917 EXPECT_EQ(factors.size(), 2);
1918}
1919
1921{
1922 // x^3 - x = x(x-1)(x+1) over F_5 (3 roots)
1923 IntPoly p;
1924 p.set_coeff(0, 0);
1925 p.set_coeff(1, -1);
1926 p.set_coeff(3, 1);
1927 auto factors = IntPoly::factor_mod_p(p, 5);
1928 EXPECT_GE(factors.size(), 1);
1929}
1930
1932{
1933 // x^2 + 1 is irreducible over F_3
1934 IntPoly p;
1935 p.set_coeff(0, 1);
1936 p.set_coeff(2, 1);
1937 auto factors = IntPoly::factor_mod_p(p, 3);
1938 EXPECT_EQ(factors.size(), 1);
1939}
1940
1942{
1943 // (x-1)(x-2)(x-3) over F_7
1944 IntPoly f1, f2, f3;
1945 f1.set_coeff(0, -1);
1946 f1.set_coeff(1, 1);
1947 f2.set_coeff(0, -2);
1948 f2.set_coeff(1, 1);
1949 f3.set_coeff(0, -3);
1950 f3.set_coeff(1, 1);
1951 IntPoly p = f1 * f2 * f3;
1952 auto factors = IntPoly::factor_mod_p(p, 7);
1953 EXPECT_GE(factors.size(), 1);
1954}
1955
1957{
1958 // (x - 1)^2 should expose the repeated linear factor over F_5.
1960 linear.set_coeff(0, -1);
1961 linear.set_coeff(1, 1);
1962
1964 ASSERT_EQ(factors.size(), 2);
1965 for (const auto &factor : factors)
1966 {
1967 EXPECT_EQ(factor.degree(), 1u);
1968 EXPECT_EQ(factor.get_coeff(1), 1);
1969 EXPECT_EQ(factor.get_coeff(0), 4);
1970 }
1971}
1972
1974{
1975 IntPoly p;
1976 p.set_coeff(0, -2);
1977 p.set_coeff(1, 1);
1978
1979 EXPECT_THROW(IntPoly::factor_mod_p(p, 1), std::domain_error);
1980 EXPECT_THROW(IntPoly::factor_mod_p(p, 0), std::domain_error);
1981 EXPECT_THROW(IntPoly::factor_mod_p(p, -5), std::domain_error);
1982}
1983
1984// --- Mignotte Bound Tests ---
1985
1987{
1988 // x - 1, degree 1, max|c| = 1 → sqrt(2)*2*1
1989 IntPoly p;
1990 p.set_coeff(0, -1);
1991 p.set_coeff(1, 1);
1992 double bound = p.mignotte_bound();
1993 EXPECT_GT(bound, 0);
1994 EXPECT_LT(bound, 10);
1995}
1996
1998{
1999 // x^4 - 1, degree 4, max|c| = 1
2000 IntPoly p;
2001 p.set_coeff(0, -1);
2002 p.set_coeff(4, 1);
2003 double bound = p.mignotte_bound();
2004 EXPECT_GT(bound, 10);
2005}
2006
2007// --- Hensel Lift Tests ---
2008
2010{
2011 // x^2 - 6 ≡ (x-1)(x+1) mod 5, and the lifted roots mod 25 are ±9.
2012 IntPoly f1, f2;
2013 f1.set_coeff(0, -1);
2014 f1.set_coeff(1, 1);
2015 f2.set_coeff(0, 1);
2016 f2.set_coeff(1, 1);
2017
2018 IntPoly f;
2019 f.set_coeff(0, -6);
2020 f.set_coeff(2, 1);
2021
2023 factors.append(f1);
2024 factors.append(f2);
2025 auto lifted = IntPoly::hensel_lift(f, factors, 5, 1);
2026 EXPECT_EQ(lifted.size(), 2);
2027
2028 IntPoly product(1);
2029 for (const auto &factor : lifted)
2030 product *= factor;
2031
2033}
2034
2036{
2037 // Lift factors from mod 3
2038 IntPoly f;
2039 f.set_coeff(0, 1);
2040 f.set_coeff(1, 1);
2041 f.set_coeff(3, 1);
2043 factors.append(f);
2044 auto lifted = IntPoly::hensel_lift(f, factors, 3, 1);
2045 EXPECT_GE(lifted.size(), 1);
2046}
2047
2049{
2050 // Lift to modulus 5^4 = 625 and preserve congruence.
2051 IntPoly f1, f2;
2052 f1.set_coeff(0, -1);
2053 f1.set_coeff(1, 1);
2054 f2.set_coeff(0, 1);
2055 f2.set_coeff(1, 1);
2056
2057 IntPoly f;
2058 f.set_coeff(0, -6);
2059 f.set_coeff(2, 1);
2060
2062 factors.append(f1);
2063 factors.append(f2);
2064 auto lifted = IntPoly::hensel_lift(f, factors, 5, 2);
2065 EXPECT_EQ(lifted.size(), 2);
2066
2067 IntPoly product(1);
2068 for (const auto &factor : lifted)
2069 product *= factor;
2070
2072}
2073
2075{
2076 // Single factor: just reduce modulo p^(2^levels)
2077 IntPoly f;
2078 f.set_coeff(0, 1);
2079 f.set_coeff(1, 1);
2081 factors.append(f);
2082 auto lifted = IntPoly::hensel_lift(f, factors, 7, 1);
2083 EXPECT_EQ(lifted.size(), 1);
2084}
2085
2087{
2088 IntPoly f;
2089 f.set_coeff(0, -6);
2090 f.set_coeff(2, 1);
2091
2092 IntPoly f1, f2;
2093 f1.set_coeff(0, -1);
2094 f1.set_coeff(1, 1);
2095 f2.set_coeff(0, 1);
2096 f2.set_coeff(1, 1);
2097
2099 factors.append(f1);
2100 factors.append(f2);
2101
2102 EXPECT_THROW(IntPoly::hensel_lift(f, factors, 1, 1), std::domain_error);
2103 EXPECT_THROW(IntPoly::hensel_lift(f, factors, 0, 1), std::domain_error);
2104 EXPECT_THROW(IntPoly::hensel_lift(f, factors, 5, 0), std::domain_error);
2105}
2106
2108{
2109 IntPoly f;
2110 f.set_coeff(0, 1);
2111 f.set_coeff(1, 1);
2112
2114 factors.append(f);
2115
2116 EXPECT_THROW(IntPoly::hensel_lift(f, factors, std::numeric_limits<long long>::max(), 1),
2117 std::domain_error);
2118}
2119
2120// --- Factorize Tests ---
2121
2123{
2124 // x^4 - 1 = (x-1)(x+1)(x^2+1) over Z
2125 IntPoly p;
2126 p.set_coeff(0, -1);
2127 p.set_coeff(4, 1);
2128 auto fact = p.factorize();
2130}
2131
2133{
2134 // x^4 + 4x^2 + 3 = (x^2 + 1)(x^2 + 3)
2135 IntPoly q1({1, 0, 1});
2136 IntPoly q2({3, 0, 1});
2137 IntPoly p = q1 * q2;
2138
2139 auto fact = p.factorize();
2140
2142
2143 bool found_q1 = false;
2144 bool found_q2 = false;
2145 for (const auto &term : fact)
2146 {
2147 if (term.multiplicity != 1)
2148 continue;
2149 found_q1 = found_q1 or (term.factor == q1);
2150 found_q2 = found_q2 or (term.factor == q2);
2151 }
2152
2155}
2156
2158{
2159 // (2x^2 + 1)(3x^2 + 2)
2160 IntPoly q1({1, 0, 2});
2161 IntPoly q2({2, 0, 3});
2162 IntPoly p = q1 * q2;
2163
2164 auto fact = p.factorize();
2165
2167
2168 bool found_q1 = false;
2169 bool found_q2 = false;
2170 for (const auto &term : fact)
2171 {
2172 if (term.multiplicity != 1)
2173 continue;
2174 found_q1 = found_q1 or (term.factor == q1);
2175 found_q2 = found_q2 or (term.factor == q2);
2176 }
2177
2180}
2181
2183{
2184 // (x^3 + x + 1)(x^3 + x + 3)
2185 IntPoly c1({1, 1, 0, 1});
2186 IntPoly c2({3, 1, 0, 1});
2187 IntPoly p = c1 * c2;
2188
2189 auto fact = p.factorize();
2190
2192
2193 bool found_c1 = false;
2194 bool found_c2 = false;
2195 for (const auto &term : fact)
2196 {
2197 if (term.multiplicity != 1)
2198 continue;
2199 found_c1 = found_c1 or (term.factor == c1);
2200 found_c2 = found_c2 or (term.factor == c2);
2201 }
2202
2205}
2206
2208{
2209 // x^3 = x * x * x (cube of linear factor)
2210 IntPoly p;
2211 p.set_coeff(3, 1);
2212 auto fact = p.factorize();
2213 // Should find x^3 or x with multiplicity 3
2214 bool found_cubic_or_triple = false;
2215 for (auto &term : fact)
2216 {
2217 if ((term.factor.degree() == 3 and term.multiplicity == 1) or
2218 (term.factor.degree() == 1 and term.multiplicity == 3))
2219 found_cubic_or_triple = true;
2220 }
2222}
2223
2225{
2226 // (x-1)^2 * (x+1) = (x^2 - 2x + 1)(x+1)
2227 IntPoly f1, f2;
2228 f1.set_coeff(0, 1);
2229 f1.set_coeff(1, -2);
2230 f1.set_coeff(2, 1);
2231 f2.set_coeff(0, 1);
2232 f2.set_coeff(1, 1);
2233 IntPoly p = f1 * f2;
2234 auto fact = p.factorize();
2236}
2237
2239{
2240 // (2x + 1)(x - 3) should be recovered exactly over Z.
2241 IntPoly f1, f2;
2242 f1.set_coeff(0, 1);
2243 f1.set_coeff(1, 2);
2244 f2.set_coeff(0, -3);
2245 f2.set_coeff(1, 1);
2246
2247 IntPoly p = f1 * f2;
2248 auto fact = p.factorize();
2249
2251
2252 bool found_two_x_plus_one = false;
2253 bool found_x_minus_three = false;
2254 for (const auto &term : fact)
2255 {
2256 if (term.multiplicity != 1)
2257 continue;
2260 }
2261
2264}
2265
2267{
2268 {
2269 IntPoly p;
2270 p.set_coeff(0, 2);
2271 p.set_coeff(1, 2);
2272
2274 x_plus_one.set_coeff(0, 1);
2275 x_plus_one.set_coeff(1, 1);
2276
2277 auto fact = p.factorize();
2278
2280
2281 bool found_content = false;
2282 bool found_linear = false;
2283 for (const auto &term : fact)
2284 {
2285 if (term.multiplicity != 1)
2286 continue;
2287 found_content = found_content or (term.factor == IntPoly(2));
2289 }
2290
2293 }
2294
2295 {
2296 IntPoly p;
2297 p.set_coeff(0, -1);
2298 p.set_coeff(1, -1);
2299
2301 x_plus_one.set_coeff(0, 1);
2302 x_plus_one.set_coeff(1, 1);
2303
2304 auto fact = p.factorize();
2305
2307
2308 bool found_content = false;
2309 bool found_linear = false;
2310 for (const auto &term : fact)
2311 {
2312 if (term.multiplicity != 1)
2313 continue;
2314 found_content = found_content or (term.factor == IntPoly(-1));
2316 }
2317
2320 }
2321}
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
Dynamic singly linked list with functional programming support.
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
Univariate polynomial over a generic coefficient ring.
Gen_Polynomial nth_derivative(size_t n) const
-th derivative .
DynList< Gen_Polynomial > sturm_chain() const
Sturm sequence of this polynomial.
Coefficient horner_eval(const Coefficient &x) const
Evaluate using gap-aware Horner's method.
Gen_Polynomial negate_arg() const
Argument negation: .
static Gen_Polynomial zero()
The zero polynomial.
void for_each_term(Op &&op) const
Iterate over non-zero terms in ascending exponent order.
static Gen_Polynomial one()
The constant polynomial 1.
Coefficient content() const
Content: GCD of all coefficients.
size_t num_terms() const noexcept
Number of non-zero terms.
DynList< size_t > exponents() const
All exponents with non-zero coefficients (sorted ascending).
static DynList< Gen_Polynomial > factor_mod_p(const Gen_Polynomial &f, Coefficient p)
Factorization over integers mod p (trial method).
Gen_Polynomial primitive_part() const
Primitive part: polynomial divided by its content.
Coefficient cauchy_bound() const
Cauchy upper bound on absolute value of roots.
Coefficient eval(const Coefficient &x) const
Evaluate with adaptive strategy.
Gen_Polynomial truncate(size_t n) const
Truncate to degree less than n.
std::string to_str(const std::string &var="x") const
Human-readable string representation.
static Gen_Polynomial from_roots(const DynList< Coefficient > &roots)
Build polynomial from its roots: .
static Gen_Polynomial interpolate(const DynList< std::pair< Coefficient, Coefficient > > &points)
Polynomial interpolation through a set of points.
bool is_constant() const noexcept
True if constant or zero.
size_t count_real_roots(const Coefficient &a, const Coefficient &b) const
Count distinct real roots in via Sturm's theorem.
Gen_Polynomial pow(size_t n) const
Exponentiation by repeated squaring.
DynList< SfdTerm > yun_sfd() const
Yun's square-free decomposition (SFD).
size_t sign_variations() const
Count sign changes in the coefficient sequence.
bool is_monomial() const noexcept
True if exactly one non-zero term.
static Xgcd_Result xgcd(Gen_Polynomial a, Gen_Polynomial b)
static Gen_Polynomial integer_gcd(Gen_Polynomial a, Gen_Polynomial b)
Polynomial GCD over integers (Euclidean algorithm with primitive parts).
double mignotte_bound() const
Mignotte bound on integer roots.
Gen_Polynomial compose(const Gen_Polynomial &q) const
Composition .
bool is_zero() const noexcept
True if this is the zero polynomial.
size_t count_all_real_roots() const
Total number of distinct real roots.
static Gen_Polynomial _integer_exact_quot(const Gen_Polynomial &a, const Gen_Polynomial &b)
Integer-safe exact quotient using pseudo-division.
Coefficient bisect_root(Coefficient a, Coefficient b, Coefficient tol=Coefficient(1e-12), size_t max_iter=200) const
Find a root by bisection in .
size_t degree() const noexcept
Degree of the polynomial.
DynList< SfdTerm > factorize() const
Main factorization over integers.
Gen_Polynomial shift_down(size_t k) const
Divide by (shift exponents down).
static DynList< Gen_Polynomial > hensel_lift(const Gen_Polynomial &f, DynList< Gen_Polynomial > factors, Coefficient p, size_t levels)
Hensel lifting of modular factors.
DynList< std::pair< size_t, Coefficient > > terms_list() const
All non-zero terms as a sorted list of (exponent, coefficient).
std::pair< Gen_Polynomial, Gen_Polynomial > divmod(const Gen_Polynomial &d) const
Polynomial long division: returns (quotient, remainder).
static Gen_Polynomial lcm(const Gen_Polynomial &a, const Gen_Polynomial &b)
Least common multiple.
Array< Coefficient > to_dense() const
Dense coefficient vector.
Gen_Polynomial shift_up(size_t k) const
Multiply by (shift exponents up).
Gen_Polynomial shift(const Coefficient &k) const
Taylor shift: .
static Gen_Polynomial gcd(Gen_Polynomial a, Gen_Polynomial b)
Greatest common divisor (Euclidean algorithm).
Gen_Polynomial square_free() const
Square-free part: .
Gen_Polynomial derivative() const
Formal derivative .
std::pair< Gen_Polynomial, Gen_Polynomial > pseudo_divmod(const Gen_Polynomial &d) const
Pseudo-division for non-field coefficient types.
Gen_Polynomial integral(const Coefficient &C=Coefficient{}) const
Formal indefinite integral with constant of integration.
static Gen_Polynomial x_to(size_t n)
The monomial .
Coefficient leading_coeff() const noexcept
Leading coefficient (of the highest-degree term).
Gen_Polynomial to_monic() const
Make monic: divide by leading coefficient.
Coefficient newton_root(Coefficient x0, Coefficient tol=Coefficient(1e-12), size_t max_iter=100) const
Find a root by Newton-Raphson iteration.
void set_coeff(size_t exp, const Coefficient &c)
Set coefficient at exponent; removes entry if zero.
Gen_Polynomial reverse() const
Reciprocal polynomial: .
Coefficient get_coeff(size_t exp) const noexcept
Coefficient accessor (read-only at exponent).
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:222
#define FAIL(msg)
#define TEST(name)
static mt19937 rng
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_exp_function > > exp(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4066
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_remainder_function > > remainder(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4115
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Definition gmpfrxx.h:4060
Gen_Polynomial< long long > IntPoly
uint64_t abs_to_u64(Int value) noexcept
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
void reverse(Itor beg, Itor end)
Reverse elements in a range.
Definition ahAlgo.H:1094
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
Definition ahAlgo.H:584
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
Gen_Polynomial< double > Polynomial
Polynomial with double coefficients.
T product(const Container &container, const T &init=T{1})
Compute product of all elements.
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
double mod(double a, double b)
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
static int * k
gsl_rng * r
Univariate polynomial ring arithmetic over generic coefficients.
DynList< int > l