My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
qf_poly.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qf_poly.cpp
3  ----------------
4  begin : Mon Jan 02 2006
5  copyright : (C) 2006 by Vincent Habchi, F5RCS
6  email : 10.50@free.fr
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 // Class for polynoms with real coefficients (R[X])
19 // Basic operations are covered
20 // It includes also an algorithm to find all the roots of a real
21 // polynom.
22 
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26 #include <iostream>
27 
28 #undef _QF_POLY_DEBUG
29 
30 #include "qf_poly.h"
31 
32 // A polynom is essentially a structure with an order (max. index)
33 // and a table storing coefficients
35  rep (NONE), d (0), krts (0), p (NULL), rts (NULL) {
36 }
37 
38 // Creates default polynoms
39 qf_poly::qf_poly (unsigned o) :
40  rep (NONE), d (o), krts (0), p (NULL), rts (NULL) {
41 }
42 
43 // This function creates irreductible real polynoms
44 // That is either constants, monoms, or binoms
46 
47 #ifdef _QF_POLY_DEBUG
48  std::cout << "qf_poly (ax^2+bx+c), a = " << a << ", b = " << b
49  << ", c = " << c << ", d° = " << deg << "\n";
50 #endif
51 
52  // Pathological cases
53  if ((deg == 2) && (a == 0)) {
54  deg = 1;
55  a = b;
56  b = c;
57  }
58  if ((deg == 1) && (a == 0)) {
59  deg = 0;
60  a = b;
61  }
62 
63  // Proceed with normal cases
64  switch (deg) {
65  case 0:
66  // Constant
67  d = 0;
68  p = new qf_double_t[1];
69  p[0] = a;
70  rts = NULL; // no root (or an infinite # of them)
71  krts = a;
72  rep = BOTH;
73  break;
74  case 1:
75  // (aX + b)
76  d = 1;
77  p = new qf_double_t[2];
78  p[0] = b;
79  p[1] = a;
80  rts = new qf_double_t[2];
81  rts[0] = ROUND_ROOT (-b / a);
82  rts[1] = 0;
83  krts = a;
84  rep = BOTH;
85  break;
86  default:
87  // Polynom of d° 2 (aX^2 + bX + c)
88  if (deg > 2)
89  std::cout << "Warning: qf_poly called with deg > 2.\n";
90  d = 2;
91  p = new qf_double_t[3];
92  p[0] = c;
93  p[1] = b;
94  p[2] = a;
95  rts = new qf_double_t[4];
96  krts = a;
97  qf_double_t dlt = (b * b - 4 * a * c);
98  if (dlt == 0) {
99  // Double root (should not occur)
100  rts[0] = rts[2] = ROUND_ROOT (-b / (2 * a));
101  rts[1] = rts[3] = 0;
102  } else if (dlt > 0) {
103  // Two real roots (should not occur)
104  rts[1] = rts[3] = 0;
105  rts[0] = ROUND_ROOT ((-b + sqrt (dlt)) / (2 * a));
106  rts[2] = ROUND_ROOT (-(b + sqrt (dlt)) / (2 * a));
107  } else {
108  // Two conjugate complex root (normal case)
109  rts[0] = rts[2] = ROUND_ROOT (-b / (2 * a));
110  rts[1] = ROUND_ROOT (sqrt (-dlt) / (2 * a));
111  rts[3] = -rts[1];
112  }
113  rep = BOTH;
114  break;
115  }
116 
117 #ifdef _QF_POLY_DEBUG
118  std::cout << "qf_poly ax^2+bx+c: ";
119  this->disp ("prod");
120 #endif
121 }
122 
123 // Creates a polynom and instantiates it out of a constant table
124 qf_poly::qf_poly (int o, const qf_double_t coef[]) :
125  rep (COEFF), d (o), krts (0), rts (NULL) {
126 
127  p = new qf_double_t[o + 1];
128  for (int i = o; i >= 0; i--) p[i] = coef[o - i];
129 
130 #ifdef _QF_POLY_DEBUG
131  std::cout << "qf_poly coeffs: ";
132  this->disp ("P");
133 #endif
134  return;
135 }
136 
137 // Creates a polynom out of its roots and a constant factor
138 // The roots are complex numbers
139 // If a root is complex, then its conjugate is also a root
140 // since the coefficients are real.
141 qf_poly::qf_poly (int o, qf_double_t k, const qf_double_t r[]) :
142  rep (ROOTS), d (o), p (NULL) {
143 
144  rts = new qf_double_t[2 * o];
145  for (int i = 0; i < 2 * o; i++)
146  rts[i] = ROUND_ROOT (r[i]);
147  krts = k;
148 
149 #ifdef _QF_POLY_DEBUG
150  std::cout << "qf_poly (roots): ";
151  this->disp ("P");
152 #endif
153  return;
154 }
155 
156 // Copy constructor
158  rep (P.rep), d (P.d), krts (0), p (NULL), rts (NULL) {
159 
160  if (rep & COEFF) {
161  p = new qf_double_t[d + 1];
162  memcpy (p, P.p, sizeof (qf_double_t) * (d + 1));
163  }
164  if (rep & ROOTS) {
165  rts = new qf_double_t[2 * d];
166  memcpy (rts, P.rts, sizeof (qf_double_t) * 2 * d);
167  krts = P.krts;
168  }
169 }
170 
171 // Assignment operator
172 // Identical to previous
174  if (&P == this) // Self copy, nothing to do
175  return (*this);
176 
177  d = P.d;
178  rep = P.rep;
179 
180  if (p != NULL) delete[] p;
181  if (rts != NULL) delete[] rts;
182  p = rts = NULL;
183  krts = 0;
184 
185  if (rep & COEFF) {
186  p = new qf_double_t[d + 1];
187  memcpy (p, P.p, sizeof (qf_double_t) * (d + 1));
188  }
189  if (rep & ROOTS) {
190  rts = new qf_double_t[2 * d];
191  memcpy (rts, P.rts, sizeof (qf_double_t) * (2 * d));
192  krts = P.krts;
193  }
194  return (*this);
195 }
196 
197 // Garbage bin
199  if (p != NULL) delete[] p;
200  if (rts != NULL) delete[] rts;
201 }
202 
203 // Basic functions.
204 
205 // Access to the element of nth order
206 // [] overload
208  if (rep == NONE) {
209  std::cout << "qf_poly::[] used on a NONE polynom.\n";
210  exit (-1);
211  }
212  if (rep & COEFF)
213  return p[i];
214  return rts[i];
215 }
216 
217 // Returns d° (order) of polynom
218 unsigned qf_poly::deg () {
219  return d;
220 }
221 
223  if (rep == NONE) {
224  std::cout << "qf_poly::k () used on a NONE polynom.\n";
225  exit (-1);
226  }
227  if (rep & ROOTS)
228  return krts;
229  return p[d];
230 }
231 
232 // Simplifies a polynom
233 // This function looks for the highest non-zero term and sets
234 // d accordingly, so that we do not perform useless operations on 0s
235 // Note that the unused 0s are not freed. We cannot do that at that
236 // time without copying, which is a ** overhead
237 // Useful after additions
238 void qf_poly::spl () {
239  int i = d;
240 
241  if (rep == NONE) {
242  std::cout << "qf_poly::spl () used on a NONE polynom.\n";
243  exit (-1);
244  }
245 
246  if (d == 0)
247  return;
248 
249  if (rep == ROOTS)
250  return;
251 
252  // We scan from highest to lowest order
253  while (i > 0) {
254  if (p[i] == 0)
255  i--;
256  else
257  break;
258  }
259  d = i;
260 
261  return;
262 }
263 
264 // Arithmetical operations
265 
266 // Negates (Unary minus : P -> -P)
268  if (rep == NONE) {
269  std::cout << "qf_poly::unary - used on a NONE polynom.\n";
270  exit (-1);
271  }
272 
273  qf_poly R (d);
274 
275  if (rep & COEFF) {
276  R.p = new qf_double_t[d + 1];
277  for (unsigned i = 0; i <= d; i++)
278  R.p[i] = -p[i];
279  }
280  if (rep & ROOTS) {
281  R.rts = new qf_double_t[2 * d];
282  memcpy (R.rts, rts, sizeof (qf_double_t) * 2 * d);
283  R.krts = -krts;
284  }
285 
286  R.rep = rep;
287  return R;
288 }
289 
290 // Addition
292  if ((Q.rep == NONE) || (P.rep == NONE)) {
293  std::cout << "qf_poly::+ used on a NONE polynom.\n";
294  exit (-1);
295  }
296 
297  if (Q.d >= P.d) {
298  qf_poly R (Q);
299  return R += P;
300  }
301  else {
302  qf_poly R (P);
303  return R += Q;
304  }
305 }
306 
307 // Self-Addition
309  if ((rep == NONE) || (P.rep == NONE)) {
310  std::cout << "qf_poly::+= used on a NONE polynom.\n";
311  exit (-1);
312  }
313 
314  // We cannot add two polynoms if one of them is under the ROOTS form
315  if (rep == ROOTS)
316  to_coeff ();
317 
318  // We add coefficients, not roots!
319  if (P.rep == ROOTS)
320  P.to_coeff ();
321 
322  if (d >= P.d) {
323  for (unsigned i = 0; i <= P.d; i++)
324  p[i] += P.p[i];
325  }
326  else {
327  qf_double_t * pp = new qf_double_t[P.d];
328  memcpy (pp, P.p, sizeof (qf_double_t) * P.d);
329  for (unsigned i = 0; i <= d; i++)
330  pp[i] += p[i];
331  delete[] p;
332  p = pp;
333  }
334 
335  if (rep & ROOTS) {
336  rep = COEFF; // We must recompute roots if needed
337  delete[] rts;
338  rts = NULL;
339  krts = 0;
340  }
341  spl (); // Simplifies
342  return (*this);
343 }
344 
345 // Substraction
347  if ((P.rep == NONE) || (Q.rep == NONE)) {
348  std::cout << "qf_poly::- used on a NONE polynom.\n";
349  exit (-1);
350  }
351 
352  if (P.d >= Q.d) {
353  qf_poly R (P);
354  return R -= Q;
355  }
356  else {
357  qf_poly R (Q);
358  return R -= P;
359  }
360 }
361 
362 // Self-Substraction
364  if ((rep == NONE) || (P.rep == NONE)) {
365  std::cout << "qf_poly::-= used on a NONE polynom.\n";
366  exit (-1);
367  }
368 
369  if (rep == ROOTS)
370  to_coeff ();
371 
372  if (P.rep == ROOTS)
373  P.to_coeff ();
374 
375  if (d >= P.d) {
376  for (unsigned i = 0; i <= P.d; i++)
377  p[i] -= P.p[i];
378  }
379  else {
380  qf_double_t * pp = new qf_double_t[P.d + 1];
381  memcpy (pp, P.p, sizeof (qf_double_t) * (P.d + 1));
382  for (unsigned i = 0; i <= P.d; i++)
383  if (i <= d)
384  pp[i] = p[i] - pp[i];
385  else
386  pp[i] = -pp[i];
387  delete[] p;
388  p = pp;
389  }
390 
391  if (rep & ROOTS) {
392  rep = COEFF; // We must recompute roots if needed
393  delete[] rts;
394  rts = NULL;
395  krts = 0;
396  }
397  spl (); // Simplifies
398  return (*this);
399 }
400 
401 // Multiplication of two polynoms
403  if ((P.rep == NONE) || (Q.rep == NONE)) {
404  std::cout << "qf_poly::* used on a NONE polynom.\n";
405  exit (-1);
406  }
407 
408  qf_poly R (P);
409  R *= Q;
410  return R;
411 }
412 
413 // Multiplication with a scalar
415  if (P.rep == NONE) {
416  std::cout << "qf_poly::* (scalar) used on a NONE polynom.\n";
417  exit (-1);
418  }
419 
420  qf_poly R (P);
421  R *= m;
422  return R;
423 }
424 
425 // Self-Multiply
427  if ((rep == NONE) || (P.rep == NONE)) {
428  std::cout << "qf_poly::*= () used on a NONE polynom.\n";
429  exit (-1);
430  }
431 
432  // Just a constant to multiply
433  if (P.d < 1) {
434  if (P.rep & COEFF)
435  return ((*this) *= P.p[0]);
436  else
437  return ((*this) *= P.krts);
438  }
439 
440  // Resizes the coefficient list
441  if (rep & COEFF) {
442  if (!(P.rep & COEFF)) P.to_coeff ();
443  qf_double_t * q = new qf_double_t[d + P.d + 1];
444  memset (q, 0, sizeof (qf_double_t) * (d + P.d + 1));
445  for (unsigned i = 0; i <= d; i++)
446  for (unsigned j = 0; j <= P.d; j++)
447  q[i + j] += p[i] * P.p[j];
448  delete[] p;
449  p = q;
450  }
451 
452  // The roots are the concatenation of the roots of both polynoms
453  if (rep & ROOTS) {
454  if (!(P.rep & ROOTS)) P.to_roots ();
455  qf_double_t * rtsp = new qf_double_t[2 * (d + P.d)];
456  memcpy (rtsp, rts, sizeof (qf_double_t) * 2 * d);
457  memcpy (&rtsp[2 * d], P.rts, sizeof (qf_double_t) * 2 * P.d);
458  delete[] rts;
459  rts = rtsp;
460  krts *= P.krts;
461  }
462 
463  d += P.d;
464  return (*this);
465 }
466 
467 // Self-Scalar-Multiply
469  if (rep == NONE) {
470  std::cout << "qf_poly::*= (scalar) used on a NONE polynom.\n";
471  exit (-1);
472  }
473 
474  if (m == 0) {
475  krts = d = 0;
476  delete[] rts;
477  delete[] p;
478  rts = p = NULL;
479  rep = COEFF;
480  return (*this);
481  }
482 
483  if (m == 1)
484  return (*this);
485 
486  if (rep & COEFF)
487  for (unsigned i = 0; i <= d; i++)
488  p[i] *= m;
489 
490  if (rep & ROOTS)
491  krts *= m;
492 
493  return (*this);
494 }
495 
496 // Test
498  if (rep == NONE)
499  return false;
500 
501  // Two polynoms can be equal only if their degree is the same
502  if (d != P.d)
503  return false;
504 
505  // We can't compare two polynoms using the roots, because they can
506  // be stored in different order, and therefore the comparison would
507  // be cumbersome. It is shorter to translate the polynoms in COEFF
508  // form, then make a comparison of each coefficient
509 
510  if (rep == ROOTS)
511  to_coeff ();
512 
513  if (P.rep == ROOTS)
514  P.to_coeff ();
515 
516  for (unsigned i = 0; i <= d; i++)
517  if (p[i] != P.p[i])
518  return false;
519 
520  return true;
521 }
522 
524  return !((*this) == P);
525 }
526 
527 bool qf_poly::is_null (void) {
528  if (rep == NONE) {
529  std::cout << "Warning qf_poly::is_null() on a NONE polynom.\n";
530  return true;
531  }
532 
533  if (d == 0)
534  return true;
535 
536  if (d > 1)
537  return false;
538 
539  if (rep & ROOTS)
540  return (krts == 0);
541  else
542  return (p[0] == 0);
543 }
544 
545 // Basic division by x^n == left shift n places
547  if (rep == NONE) {
548  std::cout << "qf_poly::<< used on a NONE polynom.\n";
549  exit (-1);
550  }
551 
552  if (n == 0)
553  return (*this);
554 
555  if (d < n)
556  return qf_poly (0, 0, 0, 0); // 0
557 
558  else if (d == n)
559  return qf_poly (p[d], 0, 0, 0); // Q(x) = P(n)
560 
561  qf_poly R;
562 
563  if (rep & COEFF) {
564  for (unsigned i = 0; i < n; i++)
565  if (p[i] != 0) {
566  std::cout << "Warning: << by " << n << " asked for but only "
567  << i << " possible.\n";
568  n = i;
569  }
570 
571  // Okay, proceed
572  R.p = new qf_double_t[d - n + 1];
573  memcpy (R.p, &(p[n]), sizeof (qf_double_t) * (d - n + 1));
574  R.d = d - n;
575  }
576 
577  if (rep & ROOTS) {
578  int nbz = n;
579  R.rts = new qf_double_t[2 * d];
580  R.krts = krts;
581 
582  // Eliminates n zero roots
583  for (unsigned i = 0, j = 0; i < 2 * d; i += 2) {
584  if ((rts[i] == 0) && (rts[i + 1] == 0) && (nbz != 0))
585  nbz--;
586 
587  else {
588  R.rts[j] = rts[i];
589  R.rts[j + 1] = rts[i + 1];
590  j += 2;
591  }
592  }
593 
594  R.d = d - n;
595 
596  // We did not found a sufficient number of zeros
597  if (nbz != 0) {
598  std::cout << "Warning: << by " << n << " asked for but only "
599  << n - nbz << " possible.\n";
600  R.d += nbz;
601  }
602  }
603 
604  R.rep = rep;
605  return R;
606 }
607 
608 // Multiplies by x^n
610  if (rep == NONE) {
611  std::cout << "qf_poly::>> used on a NONE polynom.\n";
612  exit (-1);
613  }
614 
615  if (n == 0)
616  return (*this);
617 
618  qf_poly R (d + n);
619 
620  if (rep & COEFF) {
621  R.p = new qf_double_t[d + n + 1];
622  memset (R.p, 0, sizeof (qf_double_t) * n);
623  memcpy (&(R.p[n]), p, sizeof (qf_double_t) * (d + 1));
624  }
625 
626  if (rep & ROOTS) {
627  R.rts = new qf_double_t[2 * (d + n)];
628  memset (R.rts, 0, sizeof (qf_double_t) * 2 * n); // n times root = 0
629  memcpy (&(R.rts[2 * n]), rts, sizeof (qf_double_t) * 2 * d);
630  R.krts = krts;
631  }
632 
633  R.rep = rep;
634  return R;
635 }
636 
637 // Creates the odd part of a polynom
639  qpr orep = rep;
640 
641  if (rep == NONE) {
642  std::cout << "qf_poly::odd () used on a NONE polynom.\n";
643  exit (-1);
644  }
645 
646  if (rep == ROOTS)
647  to_coeff ();
648 
649  qf_poly P (*this);
650 
651  int i = d;
652 
653  if ((i % 2) == 1)
654  i--;
655 
656  for (; i >= 0; i -= 2)
657  P.p[i] = 0;
658 
659  P.spl ();
660 
661  if ((orep == ROOTS) || (orep == BOTH))
662  P.to_roots ();
663 
664  return P;
665 }
666 
667 // Creates the even part of a polynom
669  qpr orep = rep;
670 
671  if (rep == NONE) {
672  std::cout << "qf_poly::even () used on a NONE polynom.\n";
673  exit (-1);
674  }
675 
676 
677  if (rep == ROOTS)
678  to_coeff ();
679 
680  qf_poly P (*this);
681 
682  int i = d;
683 
684  if (i == 0)
685  return P;
686 
687  if ((i % 2) == 0)
688  i--;
689 
690  for (; i >= 1; i -= 2)
691  P.p[i] = 0;
692 
693  P.spl ();
694 
695  if ((orep == ROOTS) || (orep == BOTH))
696  P.to_roots ();
697 
698  return P;
699 }
700 
701 // computes P(-X)
703  if (rep == NONE) {
704  std::cout << "qf_poly::mnx () used on a NONE polynom.\n";
705  exit (-1);
706  }
707 
708  qf_poly P (d);
709 
710  if ((rep == COEFF) || (rep == BOTH)) {
711  P.p = new qf_double_t[d + 1];
712  for (unsigned i = 0; i <= d; i++)
713  P.p[i] = ((i % 2) == 0 ? p[i] : -p[i]);
714  }
715 
716  if ((rep == ROOTS) || (rep == BOTH)) {
717  P.rts = new qf_double_t[2 * d];
718 
719  for (unsigned i = 0; i < 2 * d; i++)
720  P.rts[i] = -rts[i];
721 
722  P.krts = ((d % 2) == 0 ? krts : -krts);
723  }
724 
725  P.rep = rep;
726  return P;
727 }
728 
729 // "Half square" : P(X) * P(-X)
731  if (rep == NONE) {
732  std::cout << "qf_poly::hsq () used on a NONE polynom.\n";
733  exit (-1);
734  }
735 
736  qf_poly P (*this);
737 
738  P *= mnx ();
739 
740  return P;
741 }
742 
743 // Q(X) <- P(X^2)
745  if (rep == NONE) {
746  std::cout << "qf_poly::sqr () used on a NONE polynom.\n";
747  exit (-1);
748  }
749 
750  if (rep == ROOTS)
751  to_coeff ();
752 
753  qf_poly P (even ());
754 
755  // Contains odd order terms
756  if ((*this) != P) {
757  std::cout << "Error! qf_poly::sqr () used on a non-square polynom.\n";
758  exit (-1);
759  }
760 
761  qf_poly Q (d / 2);
762 
763  Q.p = new qf_double_t[d / 2 + 1];
764 
765  for (unsigned i = 0; i <= d / 2; i++)
766  Q.p[i] = p[2 * i];
767 
768  Q.rep = COEFF;
769 
770  if ((rep == BOTH) || (rep == ROOTS))
771  Q.to_roots ();
772 
773  return Q; // Q(X) = P(X^2)
774 }
775 
776 // Eliminates a prime factor
778  if (rep == NONE) {
779  std::cout << "qf_poly::div () used on a NONE polynom.\n";
780  exit (-1);
781  }
782 
783  i = fabs (i); // Imaginary part must be > 0
784 
785  // First examins pathological cases
786 
787  if (d == 0) {
788  std::cout << "Warning: Div () called on a constant polynom.\n";
789  return;
790  }
791 
792  if ((d == 1) && (i != 0)) {
793  std::cout << "Div () real/complex error.\n";
794  return;
795  }
796 
797  if (d == 1) {
798  if (((rep == ROOTS) || (rep == BOTH))
799  && (fabs (rts[0] - r) < ROOT_TOL)
800  && (fabs (rts[1]) < ROOT_TOL)) {
801  d = 0;
802  delete[] rts;
803  rts = NULL;
804  delete[] p;
805  p = new qf_double_t[1];
806  p[0] = krts;
807  rep = BOTH;
808  return;
809  }
810 
811  if ((rep == COEFF) && (fabs (p[0] / p[1] + r) < ROOT_TOL)) {
812  qf_double_t temp = p[1];
813  d = 0;
814  delete[] p;
815  p = new qf_double_t[1];
816  p[0] = temp;
817  delete[] rts;
818  krts = temp;
819  rep = BOTH;
820  return;
821  }
822 
823  std::cout << "Warning: Div () error. Specified factor not found.\n";
824  return;
825  }
826 
827  // Proceed to general case.
828  // If i = 0, we divide by (X - r)
829  // If i != 0, we divide by (X^2 - 2rX + r^2+i^2), that is to say
830  // by (X - (r + iI))(X - (r - iI)) where I^2 = -1
831  if (rep == COEFF)
832  to_roots ();
833 
834  qf_double_t * rtsp = new qf_double_t[2 * d];
835 
836  bool found = false;
837 
838  for (unsigned k = 0, j = 0; k < 2 * d; k += 2) {
839 #ifdef _QF_POLY_DEBUG
840  std::cout << "Div: " << fabs (rts[k] - r) << " "
841  << fabs (rts[k + 1] - i) << "\n";
842 #endif
843 
844  if ((fabs (rts[k] - r) > ROOT_TOL) || (fabs (rts[k + 1] - i) > ROOT_TOL)) {
845  rtsp[j] = rts[k];
846  rtsp[j + 1] = rts[k + 1];
847  j += 2;
848  }
849 
850  else {
851  if (i != 0)
852  // If complex root, eliminates also next root (conjugate)
853  k += 2;
854 
855  found = true;
856  }
857  }
858 
859  if (!found) {
860  delete[] rtsp;
861  std::cout << "Div () : factor not found! \n";
862  return;
863  }
864 
865  delete[] rts;
866  rts = rtsp;
867 
868  if (i == 0)
869  d--;
870  else
871  d -= 2;
872 
873  rep = ROOTS;
874 }
875 
876 // Simplifies polynoms : eliminates common roots
877 void smpf (qf_poly & N, qf_poly & D) {
878  unsigned dN = N.d;
879  unsigned dD = D.d;
880  unsigned i, j;
881 
882  std::cout << "dN: " << dN << " dD : " << dD << '\n';
883 
884  bool * Ln = new bool[dN];
885  bool * Ld = new bool[dD];
886 
887  // Init
888  for (i = 0; i < dN; i++)
889  Ln[i] = true;
890 
891  for (i = 0; i < dD; i++)
892  Ld[i] = true;
893 
894  if (N.rep == COEFF)
895  N.to_roots ();
896 
897  if (D.rep == COEFF)
898  D.to_roots ();
899 
900  // Seek for common roots
901 
902  unsigned ndN = dN;
903  unsigned ndD = dD;
904 
905  for (i = 0; i < 2 * dN; i += 2) {
906  for (j = 0; j < 2 * dD; j += 2) {
907  std::cout << "N.rts[" << i << "] = " << N.rts[i] << ", ";
908  std::cout << "D.rts[" << j << "] = " << D.rts[j] << "\n";
909  std::cout << "N.rts[" << i + 1 << "] = " << N.rts[i + 1] << ", ";
910  std::cout << "D.rts[" << j + 1 << "] = " << D.rts[j + 1] << "\n";
911  if ((Ld[j / 2]) &&
912  (fabs (N.rts[i] - D.rts[j]) < ROOT_TOL) &&
913  (fabs (N.rts[i + 1] - D.rts[j + 1]) < ROOT_TOL)) {
914  Ln[i / 2] = false; // Eliminates both roots
915  Ld[j / 2] = false;
916  ndN--;
917  ndD--;
918  std::cout << "Common root: (" << D.rts[j]
919  << ", " << D.rts[j + 1] << "i)\n";
920  break; // Direct to next root
921  }
922  }
923  }
924 
925  if (ndN != dN) { // We have simplified sth
926  qf_double_t * nrN = new qf_double_t[2 * ndN];
927  qf_double_t * nrD = new qf_double_t[2 * ndD];
928 
929  for (i = 0, j = 0; i < 2 * dN; i += 2) {
930  if (Ln[i / 2]) { // Non common root
931  nrN[j] = N.rts[i];
932  nrN[j + 1] = N.rts[i + 1];
933  j += 2;
934  }
935  }
936 
937  delete[] N.rts;
938  N.rts = nrN;
939  N.d = ndN;
940  N.rep = ROOTS;
941 
942  for (i = 0, j = 0; i < 2 * D.d; i += 2) {
943  if (Ld[i / 2]) { // Non common root
944  nrD[j] = D.rts[i];
945  nrD[j + 1] = D.rts[i + 1];
946  j += 2;
947  }
948  }
949 
950  delete[] D.rts;
951  D.rts = nrD;
952  D.d = ndD;
953  D.rep = ROOTS;
954 
955  N.to_coeff ();
956  D.to_coeff ();
957  std::cout << "ndN: " << ndN << " ndD : " << ndD << '\n';
958  }
959  delete[] Ln;
960  delete[] Ld;
961 }
962 
963 // Hurwitzes a polynom. That is to say, eliminate its roots whose real part
964 // is positive
965 void qf_poly::hurw () {
966  if (rep == NONE) {
967  std::cout << "qf_poly::hurw () used on a NONE polynom.\n";
968  return;
969  }
970 
971  if (rep == COEFF)
972  to_roots ();
973 
974  qf_double_t * rtsp = new qf_double_t[2 * d];
975  unsigned j = 0;
976 
977  for (unsigned i = 0; i < 2 * d; i += 2) {
978  if (rts[i] > 0)
979  if (rts[i + 1] == 0) // Real positive root
980  continue;
981 
982  else {
983  i += 2; // Skips conjugate
984  continue;
985  }
986 
987  else {
988  rtsp[j] = rts[i];
989  rtsp[j + 1] = rts[i + 1];
990  j += 2;
991  }
992  }
993 
994  delete[] rts;
995  rts = rtsp;
996  d = j / 2;
997 
998  if (krts < 0)
999  krts = -krts;
1000 
1001  rep = ROOTS;
1002 }
1003 
1004 // Evaluates a polynom. Computes P(a) for real a
1006  if (rep == NONE) {
1007  std::cout << "qf_poly::eval () used on a NONE polynom.\n";
1008  return 0;
1009  }
1010 
1011  if ((rep == COEFF) || (rep == BOTH)) {
1012 
1013  if (d == 0)
1014  return p[0]; // Constant
1015 
1016  qf_double_t r = p[d];
1017 
1018  for (int i = d - 1; i >= 0; i--)
1019  r = r * a + p[i];
1020 
1021  return r;
1022  }
1023  // ROOTS form : P (a) = k prod (a - r[i])
1024  if (d == 0)
1025  return krts;
1026 
1027  qf_double_t r = krts;
1028 
1029  for (unsigned i = 0; i < 2 * d; i += 2) {
1030  if (rts[i + 1] == 0) // Real root
1031  r *= (a - rts[i]);
1032 
1033  else {
1034  qf_double_t m = rts[i] * rts[i] + rts[i + 1] * rts[i + 1];
1035  qf_double_t n = -2 * rts[i];
1036 
1037  r *= (a * a + n * a + m);
1038  i += 2; // Skips conjugate (following root)
1039  }
1040  }
1041 
1042  return r;
1043 }
1044 
1045 // Evaluates a polynom P(X^2) for X^2 = c (c can be negative)
1047  return (sqr ()).eval (c);
1048 }
1049 
1050 #ifdef _QF_POLY_DEBUG
1051 // Pretty prints a polynom
1052 void qf_poly::disp (const char *name) {
1053 
1054  if (rep == NONE) {
1055  std::cout << name << "(x) is not initalized.\n";
1056  return;
1057  }
1058 
1059  if ((rep == COEFF) || (rep == BOTH)) {
1060  std::cout << name << "(x) = ";
1061  disp_c ();
1062  }
1063 
1064  if ((rep == ROOTS) || (rep == BOTH)) {
1065  std::cout << name << "(x) = ";
1066  disp_r ();
1067  }
1068 }
1069 #else
1070 void qf_poly::disp (const char *) { }
1071 #endif // _QF_POLY_DEBUG
1072 
1073 void qf_poly::disp_c (void) {
1074  if (d == 0) {
1075  std::cout << p[0] << '\n';
1076  return;
1077  }
1078 
1079  if (p[d] < 0)
1080  std::cout << "-";
1081 
1082  if (fabs (p[d]) != 1)
1083  std::cout << fabs (p[d]);
1084 
1085  if (d == 1) {
1086  std::cout << " x ";
1087  }
1088 
1089  else {
1090  std::cout << " x^" << d << ' ';
1091 
1092  for (unsigned i = d - 1; i > 1; i--) {
1093  if (p[i] == 0) // Null monome
1094  continue;
1095 
1096  if (p[i] > 0)
1097  std::cout << "+ ";
1098  else
1099  std::cout << "- ";
1100 
1101  if (fabs (p[i]) != 1)
1102  std::cout << fabs (p[i]);
1103 
1104  std::cout << " x^" << i << ' ';
1105  }
1106 
1107  if (p[1] != 0) {
1108  if (p[1] > 0)
1109  std::cout << "+ ";
1110  else
1111  std::cout << "- ";
1112 
1113  if (fabs (p[1]) != 1)
1114  std::cout << fabs (p[1]);
1115 
1116  std::cout << " x ";
1117  }
1118  }
1119 
1120  if (p[0] != 0) {
1121  if (p[0] > 0)
1122  std::cout << "+ ";
1123  else
1124  std::cout << "- ";
1125 
1126  std::cout << fabs (p[0]);
1127 
1128  }
1129  std::cout << '\n';
1130 }
1131 
1132 void qf_poly::disp_r (void) {
1133  if (krts == -1)
1134  std::cout << "- ";
1135 
1136  else if (krts != 1)
1137  std::cout << krts << ' ';
1138 
1139  for (unsigned i = 0; i < 2 * d; i += 2) {
1140  if (rts[i + 1] == 0) { // Real root
1141  std::cout << "(X";
1142 
1143  if (rts[i] == 0)
1144  std::cout << ") ";
1145 
1146  else if (rts[i] < 0)
1147  std::cout << " + " << fabs (rts[i]) << ") ";
1148 
1149  else
1150  std::cout << " - " << rts[i] << ") ";
1151  }
1152  else { // Complex conjugate root
1153  std::cout << "(X^2 ";
1154 
1155  qf_double_t m = rts[i] * rts[i] + rts[i + 1] * rts[i + 1];
1156  qf_double_t n = 2 * rts[i];
1157 
1158  if (n > 0)
1159  std::cout << "- " << n << "X ";
1160 
1161  if (n < 0)
1162  std::cout << "+ " << fabs (n) << "X ";
1163 
1164  std::cout << "+ " << m << ") ";
1165 
1166  i += 2; // Skips next root (conjugate of present one)
1167  }
1168  }
1169  std::cout << '\n';
1170 }
1171 
1172 /* This function calculates P(X) = sum (a[i] * X^i) (sum form) out of
1173  the roots (product form) P(X) = k * prod (X - r[i]) */
1174 void qf_poly::to_coeff (void) {
1175  if (rep == NONE) {
1176  std::cout << "qf_poly::to_coeff () used on a NONE polynom.\n";
1177  exit (-1);
1178  }
1179 
1180  if ((rep == COEFF) || (rep == BOTH))
1181  return;
1182 
1183  if (p != NULL)
1184  delete[] p;
1185 
1186  rep = BOTH;
1187 
1188  p = new qf_double_t[1];
1189  p[0] = krts;
1190 
1191  if ((rts == NULL) || (d == 0))
1192  return;
1193 
1194  if (d == 1) {
1195  p = new qf_double_t[2];
1196  p[0] = -krts * rts[0];
1197  p[1] = krts;
1198  return;
1199  }
1200 
1201  unsigned r = 0;
1202 
1203  do {
1204  if (rts[2 * r + 1] == 0) { // Real root
1205  qf_double_t *q = new qf_double_t[r + 2];
1206 
1207  q[0] = 0;
1208  memcpy (&(q[1]), p, sizeof (qf_double_t) * (r + 1)); // Q(X) = XP(X)
1209 
1210  for (unsigned j = 0; j < r + 1; j++)
1211  q[j] -= rts[2 * r] * p[j]; // Q(X) -= r[i]P(X)
1212 
1213  delete[] p;
1214  p = q;
1215  r++;
1216  }
1217 
1218  else { // Complex conjugate root
1219  qf_double_t m, n;
1220  qf_double_t *q = new qf_double_t[r + 3];
1221  qf_double_t *s = new qf_double_t[r + 2];
1222 
1223  m = rts[2 * r] * rts[2 * r] + rts[2 * r + 1] * rts[2 * r + 1];
1224  n = -2 * rts[2 * r];
1225 
1226  q[0] = q[1] = s[0] = 0;
1227 
1228  memcpy (&(q[2]), p, sizeof (qf_double_t) * (r + 1)); // Q(X) = X^2P(X)
1229  memcpy (&(s[1]), p, sizeof (qf_double_t) * (r + 1)); // S(X) = XP(X)
1230 
1231  for (unsigned j = 0; j < r + 1; j++) // Q(X) = (X^2 + nX + m) P(X)
1232  q[j] += n * s[j] + m * p[j];
1233 
1234  q[r + 1] += n * s[r + 1];
1235 
1236  delete[] p;
1237  delete[] s;
1238  p = q;
1239  r += 2;
1240  }
1241  }
1242  while (r < d);
1243 
1244  (*this).disp ("qf_poly::to_coeff: ");
1245 }
1246 
1247 /* The function finds the complex roots of the polynom given by:
1248  p(x) = a_{n-1} * x^{n-1} + ... a_{2} * x^{2} + a_{1} * x + a_{0}
1249  The results are stored in the vector rst, real part followed by
1250  imaginary part for each complex root. It return zero on success
1251  and non-zero otherwise. */
1252 void qf_poly::to_roots (void) {
1253  if (rep == NONE) {
1254  std::cout << "qf_poly::to_roots () used on a NONE polynom.\n";
1255  exit (-1);
1256  }
1257 
1258  int status;
1259 
1260  if ((rep == ROOTS) || (rep == BOTH))
1261  return; // Nothing to do
1262 
1263  if (d == 0)
1264  // cannot solve for only one term
1265  return;
1266 
1267  qf_matrix m (d);
1268 
1269  if (rts != NULL)
1270  delete[] rts;
1271 
1272  rts = new qf_double_t[2 * d];
1273 
1274  krts = p[d];
1275 
1276  qf_scm (m);
1277  qf_bcm (m);
1278  status = qf_qrc (m, rts);
1279 
1280  // root solving qr method failed to converge
1281  for (unsigned i = 0; i < 2 * d; i++) {
1282  if (fabs (rts[i]) <= ROOT_PREC)
1283  rts[i] = 0;
1284  else
1285  rts[i] = ROUND_ROOT (rts[i]);
1286 // std::cout << "root(" << i/2 << ") = " << rts [i] <<
1287 // " + " << rts [i+1] << " i\n" ;
1288  }
1289 
1290  rep = BOTH;
1291 }
1292 
1293 // Private functions used by qf_poly::solve
1294 
1295 // Set companion matrix.
1296 void qf_poly::qf_scm (qf_matrix & m) {
1297  unsigned int i, j;
1298  for (i = 0; i < m.n; i++)
1299  for (j = 0; j < m.n; j++)
1300  m (i, j) = 0;
1301 
1302  for (i = 1; i < m.n; i++)
1303  m (i, i - 1) = 1;
1304 
1305  for (i = 0; i < m.n; i++)
1306  m (i, m.n - 1) = -p[i] / p[m.n];
1307 }
1308 
1309 // Balance companion matrix
1310 void qf_poly::qf_bcm (qf_matrix & m) {
1311  int not_converged = 1;
1312  qf_double_t row_norm = 0;
1313  qf_double_t col_norm = 0;
1314 
1315  while (not_converged) {
1316  unsigned int i, j;
1317  qf_double_t g, f, s;
1318 
1319  not_converged = 0;
1320 
1321  for (i = 0; i < m.n; i++) {
1322  /* column norm, excluding the diagonal */
1323  if (i != m.n - 1) {
1324  col_norm = fabs (m (i + 1, i));
1325  }
1326 
1327  else {
1328  col_norm = 0;
1329 
1330  for (j = 0; j < m.n - 1; j++) {
1331  col_norm += fabs (m (j, m.n - 1));
1332  }
1333  }
1334 
1335  /* row norm, excluding the diagonal */
1336  if (i == 0) {
1337  row_norm = fabs (m (0, m.n - 1));
1338  }
1339 
1340  else if (i == m.n - 1) {
1341  row_norm = fabs (m (i, i - 1));
1342  }
1343 
1344  else {
1345  row_norm = fabs (m (i, i - 1)) + fabs (m (i, m.n - 1));
1346  }
1347 
1348  if ((col_norm == 0) || (row_norm == 0)) {
1349  continue;
1350  }
1351 
1352  g = row_norm / RADIX;
1353  f = 1;
1354  s = col_norm + row_norm;
1355 
1356  while (col_norm < g) {
1357  f *= RADIX;
1358  col_norm *= RADIX2;
1359  }
1360 
1361  g = row_norm * RADIX;
1362 
1363  while (col_norm > g) {
1364  f /= RADIX;
1365  col_norm /= RADIX2;
1366  }
1367 
1368  if ((row_norm + col_norm) < 0.95 * s * f) {
1369  not_converged = 1;
1370  g = 1 / f;
1371  if (i == 0) {
1372  m (0, m.n - 1) *= g;
1373  }
1374 
1375  else {
1376  m (i, i - 1) *= g;
1377  m (i, m.n - 1) *= g;
1378  }
1379 
1380  if (i == m.n - 1) {
1381  for (j = 0; j < m.n; j++) {
1382  m (j, i) *= f;
1383  }
1384  }
1385  else {
1386  m (i + 1, i) *= f;
1387  }
1388  }
1389  }
1390  }
1391 }
1392 
1393 // Root solver using QR method.
1394 int qf_poly::qf_qrc (qf_matrix & h, qf_double_t * zroot) {
1395  qf_double_t t = 0;
1396  unsigned int iterations, e, i, j, k, m;
1397  qf_double_t w, x, y, s, z;
1398  qf_double_t p = 0, q = 0, r = 0;
1399  int notlast;
1400  unsigned int n = d;
1401 
1402 next_root:
1403  if (n == 0)
1404  return 0;
1405  iterations = 0;
1406 
1407 next_iteration:
1408  for (e = n; e >= 2; e--) {
1409  qf_double_t a1 = fabs (h (e - 1, e - 2));
1410  qf_double_t a2 = fabs (h (e - 2, e - 2));
1411  qf_double_t a3 = fabs (h (e - 1, e - 1));
1412 
1413  if (a1 <= EPSILON * (a2 + a3))
1414  break;
1415  }
1416 
1417  x = h (n - 1, n - 1);
1418 
1419  if (e == n) {
1420  SET_COMPLEX_PACKED (zroot, n - 1, x + t, 0); /* one real root */
1421  n--;
1422  goto next_root;
1423  }
1424 
1425  y = h (n - 2, n - 2);
1426  w = h (n - 2, n - 1) * h (n - 1, n - 2);
1427 
1428  if (e == n - 1) {
1429  p = (y - x) / 2;
1430  q = p * p + w;
1431  y = sqrt (fabs (q));
1432  x += t;
1433 
1434  if (q > 0) { /* two real roots */
1435  if (p < 0)
1436  y = -y;
1437 
1438  y += p;
1439  SET_COMPLEX_PACKED (zroot, n - 1, x - w / y, 0);
1440  SET_COMPLEX_PACKED (zroot, n - 2, x + y, 0);
1441  }
1442 
1443  else {
1444  SET_COMPLEX_PACKED (zroot, n - 1, x + p, -y);
1445  SET_COMPLEX_PACKED (zroot, n - 2, x + p, y);
1446  }
1447 
1448  n -= 2;
1449  goto next_root;
1450  }
1451 
1452  /* No more roots found yet, do another iteration */
1453  if (iterations == MAX_ITERATIONS) { /* increased from 30 to 60 */
1454  /* too many iterations - give up! */
1455  return -1;
1456  }
1457 
1458  if (iterations % 10 == 0 && iterations > 0) {
1459  /* use an exceptional shift */
1460  t += x;
1461 
1462  for (i = 0; i < n; i++) {
1463  h (i, i) -= x;
1464  }
1465 
1466  s = fabs (h (n - 1, n - 2)) + fabs (h (n - 2, n - 3));
1467  y = 0.75 * s;
1468  x = y;
1469  w = -0.4375 * s * s;
1470  }
1471 
1472  iterations++;
1473 
1474  for (m = n - 2; m >= e; m--) {
1475  qf_double_t a1, a2, a3;
1476 
1477  z = h (m - 1, m - 1);
1478  r = x - z;
1479  s = y - z;
1480  p = h (m - 1, m) + (r * s - w) / h (m, m - 1);
1481  q = h (m, m) - z - r - s;
1482  r = h (m + 1, m);
1483  s = fabs (p) + fabs (q) + fabs (r);
1484  p /= s;
1485  q /= s;
1486  r /= s;
1487 
1488  if (m == e)
1489  break;
1490 
1491  a1 = fabs (h (m - 1, m - 2));
1492  a2 = fabs (h (m - 2, m - 2));
1493  a3 = fabs (h (m, m));
1494 
1495  if (a1 * (fabs (q) + fabs (r)) <= EPSILON * fabs (p) * (a2 + a3))
1496  break;
1497  }
1498 
1499  for (i = m + 2; i <= n; i++) {
1500  h (i - 1, i - 3) = 0;
1501  }
1502  for (i = m + 3; i <= n; i++) {
1503  h (i - 1, i - 4) = 0;
1504  }
1505 
1506  /* double QR step */
1507  for (k = m; k <= n - 1; k++) {
1508  notlast = (k != n - 1);
1509 
1510  if (k != m) {
1511  p = h (k - 1, k - 2);
1512  q = h (k, k - 2);
1513  r = notlast ? h (k + 1, k - 2) : 0;
1514  x = fabs (p) + fabs (q) + fabs (r);
1515 
1516  if (x == 0)
1517  continue; /* FIXME????? */
1518 
1519  p /= x;
1520  q /= x;
1521  r /= x;
1522  }
1523 
1524  s = sqrt (p * p + q * q + r * r);
1525 
1526  if (p < 0)
1527  s = -s;
1528 
1529  if (k != m) {
1530  h (k - 1, k - 2) = -s * x;
1531  } else if (e != m) {
1532  h (k - 1, k - 2) *= -1;
1533  }
1534 
1535  p += s;
1536  x = p / s;
1537  y = q / s;
1538  z = r / s;
1539  q /= p;
1540  r /= p;
1541 
1542  /* do row modifications */
1543  for (j = k; j <= n; j++) {
1544  p = h (k - 1, j - 1) + q * h (k, j - 1);
1545 
1546  if (notlast) {
1547  p += r * h (k + 1, j - 1);
1548  h (k + 1, j - 1) -= p * z;
1549  }
1550 
1551  h (k, j - 1) -= p * y;
1552  h (k - 1, j - 1) -= p * x;
1553  }
1554  j = (k + 3 < n) ? (k + 3) : n;
1555 
1556  /* do column modifications */
1557  for (i = e; i <= j; i++) {
1558  p = x * h (i - 1, k - 1) + y * h (i - 1, k);
1559 
1560  if (notlast) {
1561  p += z * h (i - 1, k + 1);
1562  h (i - 1, k + 1) -= p * r;
1563  }
1564 
1565  h (i - 1, k) -= p * q;
1566  h (i - 1, k - 1) -= p;
1567  }
1568  }
1569 
1570  goto next_iteration;
1571 }