Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
polynomial_example.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 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
71# include <iostream>
72# include <iomanip>
73# include <cmath>
74
75# include <tpl_polynomial.H>
76
77using namespace std;
78using namespace Aleph;
79
81
82
83// ─────────────────────────────────────────────────────────────────────
84// Helper: print a section header
85// ─────────────────────────────────────────────────────────────────────
86static void section(const string & title)
87{
88 cout << "\n" << string(65, '=') << "\n"
89 << " " << title << "\n"
90 << string(65, '=') << "\n\n";
91}
92
93
94// =====================================================================
95// 1. Basic Polynomial Arithmetic
96// =====================================================================
97
102static void basic_arithmetic()
103{
104 section("1. Basic Polynomial Arithmetic");
105
106 // Dense construction: coefficients in ascending exponent order
107 // p(x) = 2 + 3x + x^2
108 Polynomial p({2, 3, 1});
109 cout << " p(x) = " << p << "\n";
110
111 // q(x) = 1 - x + 4x^3
112 Polynomial q({1, -1, 0, 4});
113 cout << " q(x) = " << q << "\n\n";
114
115 // Arithmetic
116 cout << " p + q = " << (p + q) << "\n";
117 cout << " p - q = " << (p - q) << "\n";
118 cout << " p * q = " << (p * q) << "\n";
119
120 // Scalar operations
121 cout << " 3 * p = " << (p * 3.0) << "\n";
122 cout << " p / 2 = " << (p / 2.0) << "\n\n";
123
124 // Polynomial division: (x^3 - 1) / (x - 1) = x^2 + x + 1
125 Polynomial num({-1, 0, 0, 1}); // x^3 - 1
126 Polynomial den({-1, 1}); // x - 1
127 auto [quotient, remainder] = num.divmod(den);
128 cout << " (" << num << ") / (" << den << ")\n";
129 cout << " quotient = " << quotient << "\n";
130 cout << " remainder = " << remainder << "\n\n";
131
132 // Verification: num == quotient * den + remainder
134 cout << " Verify: q*d + r = " << reconstructed;
135 cout << (reconstructed == num ? " [OK]" : " [FAIL]") << "\n";
136}
137
138
139// =====================================================================
140// 2. Calculus: Differentiation and Integration
141// =====================================================================
142
148static void calculus_example()
149{
150 section("2. Symbolic Calculus");
151
152 // f(x) = 3x^4 - 2x^2 + x - 7
153 Polynomial f({-7, 1, -2, 0, 3});
154 cout << " f(x) = " << f << "\n\n";
155
156 // First derivative: f'(x) = 12x^3 - 4x + 1
157 Polynomial fp = f.derivative();
158 cout << " f'(x) = " << fp << "\n";
159
160 // Second derivative: f''(x) = 36x^2 - 4
162 cout << " f''(x) = " << fpp << "\n\n";
163
164 // Indefinite integral (constant of integration = 0)
165 Polynomial F = f.integral();
166 cout << " Integral of f(x) = " << F << "\n";
167
168 // Fundamental theorem: d/dx[integral(f)] == f
170 cout << " d/dx[integral(f)] = " << roundtrip << "\n";
171 cout << " Matches original? " << (roundtrip == f ? "Yes" : "No") << "\n\n";
172
173 // Evaluate at a point: f(2)
174 double x = 2.0;
175 cout << " f(" << x << ") = " << f(x) << "\n";
176 cout << " f'(" << x << ") = " << fp(x) << "\n";
177}
178
179
180// =====================================================================
181// 3. Root Construction and Polynomial Interpolation
182// =====================================================================
183
191{
192 section("3. Roots and Interpolation");
193
194 // --- (a) Build from roots ---
195 // Roots at x = 1, 2, 3 => (x-1)(x-2)(x-3) = x^3 - 6x^2 + 11x - 6
196 DynList<double> roots;
197 roots.append(1.0);
198 roots.append(2.0);
199 roots.append(3.0);
200
202 cout << " Polynomial with roots {1, 2, 3}:\n";
203 cout << " p(x) = " << p << "\n\n";
204
205 // Verify roots
206 cout << " Evaluation at roots:\n";
207 roots.for_each([&p](double r)
208 {
209 cout << " p(" << r << ") = " << p(r) << "\n";
210 });
211
212 // --- (b) Polynomial interpolation via Newton divided differences ---
213 // Fit a quadratic through (0, 1), (1, 0), (2, 1)
214 // Expected: (x - 1)^2 = x^2 - 2x + 1
215 cout << "\n Polynomial interpolation through (0,1), (1,0), (2,1)"
216 << " using Newton divided differences:\n";
217
219 points.append(std::make_pair(0.0, 1.0));
220 points.append(std::make_pair(1.0, 0.0));
221 points.append(std::make_pair(2.0, 1.0));
222
224 cout << " L(x) = " << interp << "\n\n";
225
226 // Verify interpolation
227 cout << " Verification:\n";
228 points.for_each([&interp](const std::pair<double, double> & pt)
229 {
230 cout << " L(" << pt.first << ") = " << interp(pt.first)
231 << " (expected " << pt.second << ")\n";
232 });
233}
234
235
236// =====================================================================
237// 4. Transfer Function (Signal Processing)
238// =====================================================================
239
245static void transfer_function()
246{
247 section("4. Transfer Function (Signal Processing)");
248
249 // H(s) = 1 / (s^2 + 1.414s + 1) — 2nd order Butterworth
250 Polynomial num(1.0); // N(s) = 1
251 Polynomial den({1, 1.414, 1}); // D(s) = 1 + 1.414s + s^2
252 cout << " H(s) = (" << num << ") / (" << den << ")\n\n";
253
254 cout << " Frequency response |H(jw)|^2 at sample points:\n";
255 cout << " " << setw(10) << "omega" << setw(15) << "|N(jw)|^2"
256 << setw(15) << "|D(jw)|^2" << setw(15) << "|H(jw)|^2" << "\n";
257 cout << " " << string(55, '-') << "\n";
258
259 // For a polynomial P(s) evaluated at s = jw we decompose P(jw)
260 // into real and imaginary parts by cycling powers of j (j^0 = 1, j^1 = j,
261 // j^2 = -1, j^3 = -j). The code below accumulates these parts in
262 // even_sum (real) and odd_sum (imag) so that |P(jw)|^2 = Re^2 + Im^2.
263 // Algebraically this matches the identity P(jw) = P_even(w^2) + jw * P_odd(w^2)
264 // because Re = P_even(w^2) and Im = w * P_odd(w^2).
265
266 auto mag_squared = [](const Polynomial & p, double w) -> double
267 {
268 // Split into even and odd parts
269 double even_sum = 0, odd_sum = 0;
270 double w2 = w * w;
271 p.for_each_term([&](size_t exp, const double & c)
272 {
273 double w_pow = pow(w2, exp / 2.0);
274 // (jw)^k = j^k * w^k. j^0=1, j^1=j, j^2=-1, j^3=-j
275 switch (exp % 4)
276 {
277 case 0: even_sum += c * w_pow; break;
278 case 1: odd_sum += c * w_pow; break;
279 case 2: even_sum -= c * w_pow; break;
280 case 3: odd_sum -= c * w_pow; break;
281 }
282 });
283 return even_sum * even_sum + odd_sum * odd_sum;
284 };
285
287 freqs.append(0.0);
288 freqs.append(0.5);
289 freqs.append(1.0);
290 freqs.append(2.0);
291 freqs.append(5.0);
292 freqs.append(10.0);
293
294 ios::fmtflags saved_flags = cout.flags();
295 streamsize saved_precision = cout.precision();
296
297 freqs.for_each([&](double w)
298 {
299 double n2 = mag_squared(num, w);
300 double d2 = mag_squared(den, w);
301 double h2 = n2 / d2;
302 cout << " " << setw(10) << fixed << setprecision(2) << w
303 << setw(15) << setprecision(6) << n2
304 << setw(15) << d2
305 << setw(15) << h2 << "\n";
306 });
307
308 cout.flags(saved_flags);
309 cout.precision(saved_precision);
310
311 cout << "\n At w=1 (cutoff), |H(j)|^2 should be ~0.5 (-3dB).\n";
312}
313
314
315// =====================================================================
316// 5. Sparse High-Degree Polynomials
317// =====================================================================
318
324{
325 section("5. Sparse High-Degree Polynomials");
326
327 // p(x) = x^1000 + x^500 + 1 (only 3 terms stored)
329 terms_p.append(std::make_pair(size_t(0), 1.0));
330 terms_p.append(std::make_pair(size_t(500), 1.0));
331 terms_p.append(std::make_pair(size_t(1000), 1.0));
333
334 cout << " p(x) = " << p << "\n";
335 cout << " degree = " << p.degree() << ", terms stored = "
336 << p.num_terms() << "\n\n";
337
338 // q(x) = x^1000 - 1
340 terms_q.append(std::make_pair(size_t(0), -1.0));
341 terms_q.append(std::make_pair(size_t(1000), 1.0));
343
344 cout << " q(x) = " << q << "\n";
345 cout << " degree = " << q.degree() << ", terms stored = "
346 << q.num_terms() << "\n\n";
347
348 // Subtraction: p - q = x^500 + 2 (cancels x^1000)
349 Polynomial diff = p - q;
350 cout << " p - q = " << diff << "\n";
351 cout << " degree = " << diff.degree() << ", terms = "
352 << diff.num_terms() << "\n\n";
353
354 // Derivative of p: 1000*x^999 + 500*x^499
355 Polynomial dp = p.derivative();
356 cout << " p'(x) = " << dp << "\n";
357 cout << " degree = " << dp.degree() << ", terms = "
358 << dp.num_terms() << "\n\n";
359
360 // Evaluate p at x = 1: 1 + 1 + 1 = 3
361 cout << " p(1) = " << p(1.0) << "\n";
362 cout << " p(0) = " << p(0.0) << "\n";
363
364 // Composition: p(2x) preserves sparsity because each term only shifts degree
365 Polynomial linear({0, 2}); // 2x
367 cout << "\n p(2x) has degree " << composed.degree()
368 << " with " << composed.num_terms() << " terms\n";
369}
370
371
372// =====================================================================
373// 6. Root Analysis and Finding
374// =====================================================================
375
380static void root_analysis()
381{
382 section("6. Root Analysis and Finding");
383
384 // p(x) = (x-1)(x-2)(x+3) = x^3 - 7x + 6... let's build it
386 cout << " p(x) = " << p << "\n";
387 cout << " degree = " << p.degree() << "\n\n";
388
389 // Cauchy bound: all roots |r| <= bound
390 double bound = p.cauchy_bound();
391 cout << " Cauchy root bound: |roots| <= " << bound << "\n";
392 cout << " (actual roots: 1, 2, -3; max |root| = 3)\n\n";
393
394 // Descartes' rule of signs
395 cout << " Sign variations of p(x): " << p.sign_variations()
396 << " (upper bound on positive roots)\n";
397 cout << " Sign variations of p(-x): " << p.negate_arg().sign_variations()
398 << " (upper bound on negative roots)\n\n";
399
400 // Sturm root counting
401 cout << " Real roots in [-10, 10]: "
402 << p.count_real_roots(-10.0, 10.0) << "\n";
403 cout << " Real roots in [0, 5]: "
404 << p.count_real_roots(0.0, 5.0) << "\n";
405 cout << " Real roots in [-5, 0]: "
406 << p.count_real_roots(-5.0, 0.0) << "\n";
407 cout << " Total real roots: "
408 << p.count_all_real_roots() << "\n\n";
409
410 // Root finding: bisection
411 cout << " Root finding (bisection):\n";
412 double r1 = p.bisect_root(0.5, 1.5);
413 double r2 = p.bisect_root(1.5, 3.0);
414 double r3 = p.bisect_root(-5.0, -1.0);
415 ios::fmtflags saved_flags = cout.flags();
416 streamsize saved_precision = cout.precision();
417 cout << " root in [0.5, 1.5]: " << fixed << setprecision(10)
418 << r1 << "\n";
419 cout << " root in [1.5, 3.0]: " << r2 << "\n";
420 cout << " root in [-5, -1]: " << r3 << "\n\n";
421
422 // Root finding: Newton-Raphson
423 cout << " Root finding (Newton-Raphson):\n";
424 r1 = p.newton_root(0.5);
425 r2 = p.newton_root(2.5);
426 r3 = p.newton_root(-2.0);
427 cout << " from x0=0.5: " << r1 << "\n";
428 cout << " from x0=2.5: " << r2 << "\n";
429 cout << " from x0=-2.0: " << r3 << "\n";
430 cout.flags(saved_flags);
431 cout.precision(saved_precision);
432}
433
434
435// =====================================================================
436// 7. Algebraic Transformations
437// =====================================================================
438
444{
445 section("7. Algebraic Transformations");
446
447 // --- Square-free part ---
448 // (x-1)^3 * (x-2) has repeated root at x=1
449 Polynomial x_minus_1({-1, 1});
450 Polynomial x_minus_2({-2, 1});
452
453 cout << " p(x) = (x-1)^3*(x-2) = " << p << "\n";
454 cout << " degree = " << p.degree()
455 << ", roots: 1 (mult 3), 2 (mult 1)\n\n";
456
458 cout << " Square-free part: " << sf << "\n";
459 cout << " degree = " << sf.degree() << " (repeated roots removed)\n\n";
460
461 // --- Exact factorization over the integers ---
462 IntPolynomial z1({1, 2}); // 2x + 1
463 IntPolynomial z2({-3, 1}); // x - 3
464 IntPolynomial z = z1 * z2;
465 auto z_fact = z.factorize();
466
467 cout << " Integer factorization:\n";
468 cout << " z(x) = " << z << "\n";
469 cout << " factors:\n";
470
472 for (const auto &term : z_fact)
473 {
474 cout << " (" << term.factor << ")^" << term.multiplicity << "\n";
475
476 IntPolynomial block(1);
477 for (size_t i = 0; i < term.multiplicity; ++i)
478 block *= term.factor;
479 z_rebuilt *= block;
480 }
481
482 cout << " reconstructed = " << z_rebuilt
483 << (z_rebuilt == z ? " [factorization OK]" : " [FAIL]") << "\n\n";
484
485 IntPolynomial q1({1, 0, 1}); // x^2 + 1
486 IntPolynomial q2({3, 0, 1}); // x^2 + 3
488 auto q_fact = z_quartic.factorize();
489
490 cout << " quartic z2(x) = " << z_quartic << "\n";
491 cout << " quadratic factors:\n";
492
494 for (const auto &term : q_fact)
495 {
496 cout << " (" << term.factor << ")^" << term.multiplicity << "\n";
497
498 IntPolynomial block(1);
499 for (size_t i = 0; i < term.multiplicity; ++i)
500 block *= term.factor;
501 q_rebuilt *= block;
502 }
503
504 cout << " reconstructed = " << q_rebuilt
505 << (q_rebuilt == z_quartic ? " [factorization OK]" : " [FAIL]") << "\n\n";
506
507 IntPolynomial c1({1, 1, 0, 1}); // x^3 + x + 1
508 IntPolynomial c2({3, 1, 0, 1}); // x^3 + x + 3
510 auto c_fact = z_sextic.factorize();
511
512 cout << " sextic z3(x) = " << z_sextic << "\n";
513 cout << " cubic factors:\n";
514
516 for (const auto &term : c_fact)
517 {
518 cout << " (" << term.factor << ")^" << term.multiplicity << "\n";
519
520 IntPolynomial block(1);
521 for (size_t i = 0; i < term.multiplicity; ++i)
522 block *= term.factor;
523 c_rebuilt *= block;
524 }
525
526 cout << " reconstructed = " << c_rebuilt
527 << (c_rebuilt == z_sextic ? " [factorization OK]" : " [FAIL]") << "\n\n";
528
529 // --- Extended GCD (Bezout identity) ---
530 Polynomial a({-1, 0, 1}); // x^2 - 1
531 Polynomial b({-1, 1}); // x - 1
532 auto [g, s, t] = Polynomial::xgcd(a, b);
533
534 cout << " Extended GCD:\n";
535 cout << " a(x) = " << a << "\n";
536 cout << " b(x) = " << b << "\n";
537 cout << " gcd = " << g << "\n";
538 cout << " s(x) = " << s << "\n";
539 cout << " t(x) = " << t << "\n";
540
541 Polynomial bezout = s * a + t * b;
542 cout << " s*a + t*b = " << bezout
543 << (bezout == g ? " [Bezout OK]" : " [FAIL]") << "\n\n";
544
545 // --- Polynomial reversal ---
546 Polynomial q({1, 2, 3, 4}); // 1 + 2x + 3x^2 + 4x^3
547 cout << " Reversal:\n";
548 cout << " p(x) = " << q << "\n";
549 cout << " rev(x) = " << q.reverse() << "\n";
550 cout << " (reverses coefficient order: a_i -> a_{d-i})\n\n";
551
552 // --- Taylor shift ---
553 Polynomial f({0, 0, 1}); // x^2
554 cout << " Taylor shift:\n";
555 cout << " f(x) = " << f << "\n";
556 cout << " f(x+2) = " << f.shift(2.0) << "\n";
557 cout << " f(x-1) = " << f.shift(-1.0) << "\n";
558}
559
560
561// =====================================================================
562// Main
563// =====================================================================
564
565int main()
566{
567 cout << string(65, '*') << "\n";
568 cout << " Aleph-w Polynomial Example\n";
569 cout << " Gen_Polynomial<Coefficient> — Sparse Polynomial Arithmetic\n";
570 cout << string(65, '*') << "\n";
571
579
580 cout << "\n" << string(65, '*') << "\n";
581 cout << " All examples completed successfully.\n";
582 cout << string(65, '*') << "\n";
583
584 return 0;
585}
long double w
Definition btreepic.C:153
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 .
Gen_Polynomial negate_arg() const
Argument negation: .
void for_each_term(Op &&op) const
Iterate over non-zero terms in ascending exponent order.
size_t num_terms() const noexcept
Number of non-zero terms.
Coefficient cauchy_bound() const
Cauchy upper bound on absolute value of roots.
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.
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.
size_t sign_variations() const
Count sign changes in the coefficient sequence.
static Xgcd_Result xgcd(Gen_Polynomial a, Gen_Polynomial b)
Gen_Polynomial compose(const Gen_Polynomial &q) const
Composition .
size_t count_all_real_roots() const
Total number of distinct real roots.
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.
std::pair< Gen_Polynomial, Gen_Polynomial > divmod(const Gen_Polynomial &d) const
Polynomial long division: returns (quotient, remainder).
Gen_Polynomial shift(const Coefficient &k) const
Taylor shift: .
Gen_Polynomial square_free() const
Square-free part: .
Gen_Polynomial derivative() const
Formal derivative .
Gen_Polynomial integral(const Coefficient &C=Coefficient{}) const
Formal indefinite integral with constant of integration.
Coefficient newton_root(Coefficient x0, Coefficient tol=Coefficient(1e-12), size_t max_iter=100) const
Find a root by Newton-Raphson iteration.
Gen_Polynomial reverse() const
Reciprocal polynomial: .
void for_each(Operation &operation)
Traverse all the container and performs an operation on each element.
Definition ah-dry.H:779
__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< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_pow_function > > pow(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4061
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
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.
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
STL namespace.
static void roots_and_interpolation()
Two ways to build polynomials from known data: (a) from_roots: given roots r1, r2,...
static void algebraic_transformations()
Demonstrates square-free factorization, extended GCD (Bezout identity), polynomial reversal,...
static void calculus_example()
Symbolic differentiation and integration, verifying the Fundamental Theorem of Calculus: the derivati...
static void root_analysis()
Demonstrates Sturm sequences, root counting, Cauchy bounds, Descartes' rule of signs,...
static void sparse_polynomials()
Demonstrates efficiency of sparse representation by constructing polynomials with very high degree bu...
static void basic_arithmetic()
Demonstrates polynomial construction, printing, and the four basic arithmetic operations.
static void section(const string &title)
int main()
static void transfer_function()
A simple low-pass filter transfer function H(s) = N(s) / D(s).
gsl_rng * r
Univariate polynomial ring arithmetic over generic coefficients.