Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
PolynomialSolve.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 #include "Base/Common/W32Compat.hh"
25 #include <bias_config.h>
26 #include "PolynomialSolve.hh"
27 #include "Minpack.hh"
28 
29 #ifdef BIAS_HAVE_GSL
30 #include <gsl/gsl_poly.h>
31 #include <gsl/gsl_errno.h>
32 #endif
33 
34 #include <Base/Common/BIASpragma.hh>
35 #include <Base/Common/CompareFloatingPoint.hh>
36 #include <MathAlgo/Laguerre.hh>
37 #include <MathAlgo/SVD.hh>
38 #include <iostream>
39 #include <algorithm>
40 
41 using namespace BIAS;
42 using namespace std;
43 
44 #define DOUBLE_MIN 1e-6
45 #define PS_DOUBLE_EPSILON DBL_EPSILON
46 
47 int PolynomialSolve::Solve(const vector<POLYNOMIALSOLVE_TYPE>& ocoeff,
48  vector<POLYNOMIALSOLVE_TYPE>& sol)
49 {
50 
51  BIASASSERT(!ocoeff.empty());
52 
53  vector<POLYNOMIALSOLVE_TYPE> coeff = ocoeff;
54  CheckCoefficients(coeff);
55 
56  int deg=(int)coeff.size()-1;
57  int num=deg;
58 
59 
60  sol.clear();
61  switch (deg){
62  // zero order
63  case -1: sol.push_back(0);
64  return 1;
65  case 0: return 0; // cannot have solution, 0=0 is not possible here
66  case 1:
67  num = Linear(coeff, sol);
68  break;
69  case 2:
70  num = Quadratic(coeff, sol);
71  break;
72  case 3:
73  num = Cubic(coeff, sol);
74  break;
75  case 4:
76  num = Quartic(coeff, sol);
77  break;
78  default:
79  return Numeric(ocoeff, sol);
80  break;
81  }
82  NonLinearRefine(coeff,sol);
83 
84  return num;
85 }
86 
87 int PolynomialSolve::Solve(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
88  vector<complex<POLYNOMIALSOLVE_TYPE> >& sol)
89 {
90  int deg=(int)coeff.size()-1;
91  int num=deg;
92  BIASASSERT(deg>=0);
93  switch (deg){
94  case 0:
95  sol.clear();
96  num=0;
97  break;
98  case 1:
99  num = Linear(coeff, sol);
100  break;
101  case 2:
102  num = Quadratic(coeff, sol);
103  break;
104  case 3:
105  num = Cubic(coeff, sol);
106  break;
107  default:
108  num = Numeric(coeff, sol);
109  break;
110  }
111  return num;
112 }
113 
114 
115 int PolynomialSolve::Numeric(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
116  vector<POLYNOMIALSOLVE_TYPE>& sol)
117 {
118  vector<complex<POLYNOMIALSOLVE_TYPE> > csol;
119  int res=Numeric(coeff, csol), num=0;
120  sol.clear();
121  sol.reserve(coeff.size()-1);
122  if (res>0){
123  for (int i=0; i<res; i++){
124  if (csol[i].imag()==0.0){
125  sol.push_back(csol[i].real());
126  }
127  }
128  num=sol.size();
129  } else {
130  num=res;
131  }
132  return num;
133 }
134 
135 int PolynomialSolve::Numeric(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
136  vector<complex<POLYNOMIALSOLVE_TYPE> >& sol)
137 {
138  int deg=(int)coeff.size()-1;
139 #ifdef BIAD_DEBUG
140  if (coeff[deg]==0.0){
141  BIASERR("leading coefficient is zero, aborting"););
142  }
143 #endif
144  BIASASSERT(coeff[deg]!=0.0);
145  BIASASSERT(deg>=0);
146 
147  int num=0;
148 #ifdef BIAS_HAVE_GSL
149 
150 
151  if (deg>0){
152 #ifdef BIAS_DEBUG
153  for (unsigned i=0; i<coeff.size(); i++){
154  BIASCDOUT(D_PS_GSL, setw(3)<<i<<"th coeff: "<<coeff[i]<<endl);
155  }
156 #endif
157  size_t n=deg+1;
158  double *a=new double[n];
159  double *z=new double[2*deg];
160  gsl_poly_complex_workspace *w=gsl_poly_complex_workspace_alloc(n);
161 
162  for (unsigned i=0; i<n; i++) a[i]=coeff[i];
163  int res = gsl_poly_complex_solve(a, n, w, z);
164  gsl_poly_complex_workspace_free(w);
165  if (res==GSL_SUCCESS){
166  sol.reserve(n-1);
167  sol.clear();
168  n--;
169  for (unsigned i=0; i<n; i++){
170  sol.push_back(complex<double>(z[i<<1], z[(i<<1)+1]));
171  BIASCDOUT(D_PS_GSL, setw(3)<<i<<"th solution : "<< *sol.rbegin()
172  <<"\tpoly("<<z[i<<1]<<") = "
173  <<gsl_poly_eval(a, n+1, z[i<<1]) << endl);
174  }
175  delete a;
176  delete z;
177  num=n;
178  } else {
179  sol.clear();
180  num=-1;
181  }
182  } else {
183  sol.clear();
184  num=0;
185  }
186 #else
187 
188 // deg=0;
189 // sol.clear();
190 // BIASERR("gsl needed for PolynomialSolve::Numeric");
191 // num=-1;
192  if(deg>0)
193  {
194  LaguerreSolver l;
195  l.Solve(coeff,sol);
196  //find number of real solutions
197  num = 0;
198  // cout<<endl<<"xxxxxxxxxxxxxx size of sol -> "<<sol.size()<<endl;
199  for (unsigned int i=0; i<sol.size(); i++)
200  {
201  // cout<<sol[i]<<endl;
202  if (Equal(sol[i].imag(),0.0,10e-11))
203  {
204  sol[i]=std::complex< double>(sol[i].real(),0.0);
205  num++;
206  }
207  }
208  }
209  else
210  {
211 
212  sol.clear();
213  num=0;
214  }
215 
216 #endif
217  return num;
218 }
219 
220 
221 
222 
223 
224 int PolynomialSolve::Analytic(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
225  vector<POLYNOMIALSOLVE_TYPE>& sol)
226 {
227  int deg=(int)coeff.size()-1;
228  BIASASSERT(deg<=4);
229  int num=0;
230  switch (deg){
231  case 0:
232  sol.clear();
233  num=0;
234  break;
235  case 1:
236  num = Linear(coeff, sol);
237  break;
238  case 2:
239  num = Quadratic(coeff, sol);
240  break;
241  case 3:
242  num = Cubic(coeff, sol);
243  break;
244  case 4:
245  num = Quartic(coeff, sol);
246  break;
247  default:
248  BIASERR("something strange happened");
249  BIASABORT;
250  break;
251  }
252  return num;
253 }
254 
255 int PolynomialSolve::Analytic(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
256  vector<complex<POLYNOMIALSOLVE_TYPE> >& sol)
257 {
258  int deg=(int)coeff.size()-1;
259  BIASASSERT(deg<=3);
260  int num=0;
261  switch (deg){
262  case 0:
263  sol.clear();
264  num=0;
265  break;
266  case 1:
267  num = Linear(coeff, sol);
268  break;
269  case 2:
270  num = Quadratic(coeff, sol);
271  break;
272  case 3:
273  num = Cubic(coeff, sol);
274  break;
275  default:
276  BIASERR("something strange happened");
277  BIASABORT;
278  break;
279  }
280  return num;
281 }
282 
283 
284 
285 
286 
287 
288 
289 int PolynomialSolve::Linear(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
290  vector<POLYNOMIALSOLVE_TYPE>& sol)
291 {
292  int deg=(int)coeff.size()-1;
293 #ifdef BIAS_DEBUG
294  if(deg!=1 || coeff[deg]==0.0){
295  BIASERR("coeff is not a polynom of first order");
296  }
297 #endif
298  BIASASSERT(deg==1);
299  BIASASSERT(coeff[deg]!=0.0);
300 
301  sol.resize(deg);
302  // degree 1 has one solution
303  sol[0] = -coeff[0] / coeff[1];
304 
305  return 1;
306 }
307 
308 int PolynomialSolve::Linear(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
309  vector<complex<POLYNOMIALSOLVE_TYPE> >& sol)
310 {
311  vector<POLYNOMIALSOLVE_TYPE> rsol;
312  int deg=Linear(coeff, rsol);
313  sol.resize(deg);
314  if (deg!=0)
315  sol[0] = complex<POLYNOMIALSOLVE_TYPE>(rsol[0], 0.0);
316  return 1;
317 }
318 
319 
320 
321 
322 int PolynomialSolve::Quadratic(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
323  vector<POLYNOMIALSOLVE_TYPE>& sol)
324 {
325 
326  int deg=(int)coeff.size()-1;
327 #ifdef BIAS_DEBUG
328  if(deg!=2 || coeff[deg]==0.0){
329  BIASERR("coeff is not a polynom of second order");
330  }
331 #endif
332  BIASASSERT(deg==2);
333  BIASASSERT(coeff[deg]!=0.0);
334  int num=0;
335 
336  sol.clear();
337  sol.reserve(deg);
338 #ifdef BIAS_HAVE_GSL
339  POLYNOMIALSOLVE_TYPE s[2];
340  num=gsl_poly_solve_quadratic(coeff[2], coeff[1],coeff[0],&(s[0]),&(s[1]));
341  if (num==2 && s[0]==s[1]) num=1;
342  for (int i=0; i<num; i++) sol.push_back(s[i]);
343 #else
344  // compute normal coefficients
345  POLYNOMIALSOLVE_TYPE q1 = coeff[1] / (coeff[2] * 2.0);
346  POLYNOMIALSOLVE_TYPE q0 = coeff[0] / coeff[2];
347 
348  // get discriminant and accuracy
349  POLYNOMIALSOLVE_TYPE discriminant = q1*q1 - q0;
350  POLYNOMIALSOLVE_TYPE epsilon_d =
351  (fabs(discriminant)+7.0*q1*q1+3.0*fabs(q0)) * DBL_EPSILON;
352 
353  // check whether there is no solution
354  if (discriminant < -epsilon_d) {
355  num = 0;
356  } else if (discriminant <= epsilon_d) { // we have solutions, check how many
357  // within our accuracy, we have two identical solutions !
358  sol.push_back(-q1);
359  num = 1;
360  } else {
361  // we have two distinct roots in IR
362  // compute first one according to sign of q1:
363  POLYNOMIALSOLVE_TYPE FirstRoot =
364  ((q1>0.0)?-sqrt(discriminant):sqrt(discriminant)) - q1;
365  sol.push_back(FirstRoot);
366 
367  // avoid cancellation when calculating second root:
368  sol.push_back(q0/FirstRoot);
369  num=2;
370  }
371 #endif
372  return num;
373 }
374 
375 int PolynomialSolve::Quadratic(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
376  vector<complex<POLYNOMIALSOLVE_TYPE> >& sol)
377 {
378  int deg=(int)coeff.size()-1;
379 #ifdef BIAS_DEBUG
380  if(deg!=2 || coeff[deg]==0.0){
381  BIASERR("coeff is not a polynom of second order");
382  }
383 #endif
384  BIASASSERT(deg==2);
385  BIASASSERT(coeff[deg]!=0.0);
386  int num=0;
387 
388  sol.resize(deg);
389 #ifdef BIAS_HAVE_GSL
390  double z[4];
391  num = gsl_poly_complex_solve_quadratic(coeff[2], coeff[1], coeff[0],
392  (gsl_complex*)&(z[0]),
393  (gsl_complex*)&(z[2]));
394  sol[0]=complex<POLYNOMIALSOLVE_TYPE>(z[0], z[1]);
395  sol[1]=complex<POLYNOMIALSOLVE_TYPE>(z[2], z[3]);
396 #else
397  BIASERR("Quadratic(vector<double>, vbector<complex<double>>) only "
398  <<"implemented with gsl");
399  num = -1;
400 #endif
401  return num;
402 }
403 
404 
405 
406 
407 
408 int PolynomialSolve::Cubic(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
409  std::vector<POLYNOMIALSOLVE_TYPE>& sol)
410 {
411 #ifdef BIAS_DEBUG
412  int deg=(int)coeff.size()-1;
413  if(deg!=3 || coeff[deg]==0.0){
414  BIASERR("coeff is not a polynom of third order");
415  }
416 #endif
417  BIASASSERT(deg==3);
418  BIASASSERT(coeff[deg]!=0.0);
419  int num=0;
420  sol.reserve(3);
421 
422 #ifdef BIAS_HAVE_GSL
423  POLYNOMIALSOLVE_TYPE msol[3];
424  num = gsl_poly_solve_cubic(coeff[2]/coeff[3], coeff[1]/coeff[3],
425  coeff[0]/coeff[3], &(msol[0]),
426  &(msol[1]), &(msol[2]));
427  for (int i=0; i<num; i++)
428  sol.push_back(msol[i]);
429 #else
430  // normalize to first coefficient, i.e. a3=1
431  POLYNOMIALSOLVE_TYPE a0 = coeff[0] / coeff[3];
432  POLYNOMIALSOLVE_TYPE a1 = coeff[1] / coeff[3];
433 
434  // substitute x=z-a2/3
435  // quadratic term goes away
436  POLYNOMIALSOLVE_TYPE a2 = coeff[2] / (coeff[3] * 3.0);
437 
438  POLYNOMIALSOLVE_TYPE q = a1 / 3.0 - a2*a2;
439  POLYNOMIALSOLVE_TYPE r = ( a1*a2 - a0 ) * 0.5 - a2*a2*a2 ;
440 
441  // see if we can factorize to z==0
442  if (fabs(r)<PS_DOUBLE_EPSILON) {
443  // yes, its the easy way
444  // rest is z^2 + 3q == 0
445  if (q>-PS_DOUBLE_EPSILON) {
446  // no other solutions apart from z==0
447  // (or z==0 is a triple zero crossing)
448  // back-substitute to x
449  sol.push_back(-a2);
450  num = 1;
451  } else {
452  POLYNOMIALSOLVE_TYPE t = sqrt( -3.0 * q );
453  sol.resize(3);
454  sol[0] = -a2 - t;
455  sol[1] = -a2;
456  sol[2] = -a2 + t;
457  num = 3;
458  }
459  } else {
460 
461  // now we have z^3 + 3qz + r = 0
462  POLYNOMIALSOLVE_TYPE d = q*q*q + r*r;
463 
464  // can we directly factorize the polynomial into linear and quadratic:
465  if (fabs(d) < PS_DOUBLE_EPSILON) {
466  r = cbrt(r);
467  sol.resize(2);
468  sol[0] = 2.0*r - a2;
469  sol[1] = -r - a2;
470  num = 2;
471  } else {
472 
473  // no, we got an offset
474  if (d > 0.0) {
475  // quadratic has two imaginary sols
476  // only one real solution
477  POLYNOMIALSOLVE_TYPE s1,s2;
478 
479  d = sqrt(d);
480 
481  s1 = cbrt(r + d);
482  s2 = cbrt(r - d);
483 
484  sol.push_back(s1 + s2 - a2);
485  return 1;
486  }
487 
488  // the general case: d<0
489  // need to think in complex plane
490  d = sqrt(-d);
491  q = atan2(d,r) / 3.0;
492  r = cbrt(hypot(d,r));
493 
494  POLYNOMIALSOLVE_TYPE s = 2.0 * r * cos(q);
495  POLYNOMIALSOLVE_TYPE t = fabs(2.0 * r * sin(q)) * sin(60.0*M_PI/180.0);
496 
497  sol.resize(3);
498  sol[0] = s + -a2 ;
499  sol[1] = -0.5*s -a2 - t;
500  sol[2] = -0.5*s -a2 + t;
501  num=3;
502  }
503  }
504 #endif
505  return num;
506 }
507 
508 int PolynomialSolve::Cubic(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
509  vector<complex<POLYNOMIALSOLVE_TYPE> >& sol)
510 {
511 #ifdef BIAS_DEBUG
512  int deg=(int)coeff.size()-1;
513  if(deg!=3 || coeff[deg]==0.0){
514  BIASERR("coeff is not a polynom of third order");
515  }
516 #endif
517  BIASASSERT(deg==3);
518  BIASASSERT(coeff[deg]!=0.0);
519  int num=0;
520 
521 #ifdef BIAS_HAVE_GSL
522  double z[6];
523  num = gsl_poly_complex_solve_cubic(coeff[2]/coeff[3], coeff[1]/coeff[3],
524  coeff[0]/coeff[3], (gsl_complex*)&(z[0]),
525  (gsl_complex*)&(z[2]),
526  (gsl_complex*)&(z[4]));
527  for (int i=0; i<num; i++){
528  sol.push_back(complex<POLYNOMIALSOLVE_TYPE>(z[2*i], z[2*i+1]));
529  }
530 // sol[0]=complex<POLYNOMIALSOLVE_TYPE>(z[0], z[1]);
531 // sol[1]=complex<POLYNOMIALSOLVE_TYPE>(z[2], z[3]);
532 // sol[2]=complex<POLYNOMIALSOLVE_TYPE>(z[4], z[5]);
533 #else
534  sol.clear();
535  BIASERR("gsl needed for PolynomialSolve::Cubic(vector, vector<complex>)");
536  num=-1;
537 #endif
538  return num;
539 }
540 
541 
542 int PolynomialSolve::Quartic(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
543  vector<POLYNOMIALSOLVE_TYPE>& sol)
544 {
545  //BUG: Unknown bug, and unclear who reported the bug!
546  BIASWARN("ATTENTION! there seems to be a bug in Quartic()!");
547  int deg=(int)coeff.size()-1;
548 #ifdef BIAS_DEBUG
549  if(deg!=4 || coeff[deg]==0.0){
550  BIASERR("coeff is not a polynom of fourth order");
551  }
552 #endif
553  BIASASSERT(coeff[deg]!=0.0);
554  BIASASSERT(deg==4);
555  int num=0;
556 
557  sol.clear();
558  sol.reserve(deg);
559 
560 #ifdef BIAS_HAVE_GSL
561  // BIASERR("no gsl implementation of quartic polynomial available");
562 #endif
563 
564  vector<POLYNOMIALSOLVE_TYPE> CubicCoeffs, CubicSolutions;
565  CubicCoeffs.resize(4);
566 
567  // normalize to highest order coeficient a4==1
568  POLYNOMIALSOLVE_TYPE a0 = coeff[0] / coeff[4];
569  POLYNOMIALSOLVE_TYPE a1 = coeff[1] / coeff[4];
570  POLYNOMIALSOLVE_TYPE a2 = coeff[2] / coeff[4];
571  POLYNOMIALSOLVE_TYPE a3 = coeff[3] / coeff[4];
572 
573  CubicCoeffs[0] = -( a1*a1 + a0 * a3 * a3 - 4.0 * a0 * a2 );
574  CubicCoeffs[1] = a1*a3 - 4.0 * a0;
575  CubicCoeffs[2] = -a2;
576  CubicCoeffs[3] = 1.0;
577 
578  // unsigned int s =
579  Cubic(CubicCoeffs, CubicSolutions);
580  // cout <<"solveCubic returned "<<s<<" solutions."<<endl;
581 
582  for(unsigned int i = 0 ; i < CubicSolutions.size() ; i++ ) {
583  POLYNOMIALSOLVE_TYPE u,s,t;
584  u = CubicSolutions[i];
585 
586  s = a3*a3 / 4.0 + u - a2;
587  t = u * u / 4.0 - a0;
588 
589  if ((s>-DOUBLE_MIN) && (t>-DOUBLE_MIN)) {
590  if (s<DOUBLE_MIN) s=0;
591  if (t<DOUBLE_MIN) t=0;
592 
593  vector<POLYNOMIALSOLVE_TYPE> QuadraticCoeffs, QuadraticSolutions;
594  QuadraticCoeffs.resize(3);
595 
596  s = sqrt(s);
597  t = sqrt(t);
598 
599  // check sign of t
600  if ((s*t>0.0)^(a3*u/2.0-a1>0.0)) t = -t;
601 
602  QuadraticCoeffs[0] = u / 2.0 + t;
603  QuadraticCoeffs[1] = a3 / 2.0 + s;
604  QuadraticCoeffs[2] = 1.0;
605  Quadratic(QuadraticCoeffs, QuadraticSolutions);
606 
607  QuadraticCoeffs[0] = u / 2.0 - t;
608  QuadraticCoeffs[1] = a3 / 2.0 - s;
609  Quadratic(QuadraticCoeffs, sol);
610 
611  for (unsigned int j=0; j<QuadraticSolutions.size(); j++)
612  sol.push_back(QuadraticSolutions[j]);
613  // cout << "SolveQuartic has "<<Solutions.size()<<" solutions: ";
614  // for (int g=0; g<Solutions.size(); g++) cout << Solutions[g]<<" ";
615  // cout <<endl;
616  num = sol.size();
617  } else {
618  // cout <<"s="<<s<<" t="<<t<<endl;
619  }
620  }
621  return num;
622 }
623 
624 void PolynomialSolve::CheckCoefficients(vector<POLYNOMIALSOLVE_TYPE>& coeff,
625  double eps)
626 {
627  // find largest polynomial coefficient
628  POLYNOMIALSOLVE_TYPE largestcoeff=0;
629  for (unsigned int i=0; i<coeff.size(); i++) {
630  if (fabs(coeff[i])>largestcoeff) largestcoeff = fabs(coeff[i]);
631  }
632  if (largestcoeff>0.0) {
633  // normalize by next power of two of largest coefficient, so largest
634  // coefficient is close to 1, but we dont get any loss in precision.
635  largestcoeff = exp2(-1.0*rint(log2(largestcoeff)));
636  for (unsigned int i=0; i<coeff.size(); i++) {
637  coeff[i] *= largestcoeff;
638  }
639  } else {
640  coeff.clear();
641  return;
642  }
643  // this is now relative checking
644  while (fabs(*coeff.rbegin())<=eps && coeff.size()>0){
645  BIASCDOUT(D_PS_COEFF, "removing leading zero: "<<*coeff.rbegin()<<endl);
646  coeff.pop_back();
647  }
648 }
649 
650 void PolynomialSolve::CalCoefficients(const vector<POLYNOMIALSOLVE_TYPE>& sol,
651  vector<POLYNOMIALSOLVE_TYPE>& coeff)
652 {
653  int deg=(int)sol.size();
654  int nc=deg+1;
655  coeff.resize(nc);
656  for (int c=0; c<nc; c++){
657  BIASCDOUT(D_PS_COEFF, "\ncoff["<<c<<"] = ");
658  coeff[c]=_GetCoeff(c, 0, sol);
659  BIASCDOUT(D_PS_COEFF, " = "<<coeff[c]<<endl);
660  }
661 }
662 
663 POLYNOMIALSOLVE_TYPE
664 PolynomialSolve::_GetCoeff(int order, int begin,
665  const vector<POLYNOMIALSOLVE_TYPE>& sol)
666 {
667  POLYNOMIALSOLVE_TYPE sum=0.0;
668  int size=(int)sol.size();
669  if (order==size){
670  sum=1.0;
671  BIASCDOUT(D_PS_COEFF, sum);
672  } else if (order==0){
673  sum=-sol[0];
674  BIASCDOUT(D_PS_COEFF, -sol[0]);
675  for (int i=1; i<size; i++) {
676  sum*=-sol[i];
677  BIASCDOUT(D_PS_COEFF, "*"<<-sol[i]);
678  }
679  } else {
680  sum=0.0;
681  vector<POLYNOMIALSOLVE_TYPE> msol=sol;
682  for (int i=begin; i<size; i++){
683  msol=sol;
684  // remove (i)th element from msol
685  msol.erase(msol.begin()+i);
686 #ifdef BIAS_DEBUG
687  if (order-1==0) { BIASCDOUT(D_PS_COEFF, " + "); }
688 #endif
689  sum+=_GetCoeff(order-1, i, msol);
690  }
691  }
692  return sum;
693 }
694 
695 int PolynomialSolve::GetNumberOfRealSolutions(const vector<POLYNOMIALSOLVE_TYPE>& coeff)
696 {
697  vector<POLYNOMIALSOLVE_TYPE> sol;
698  // Poor implementation of GetNumberOfRealsol().
699  // Actually computes all solutions and throws them away.
700  return (Solve(coeff, sol));
701 }
702 
703 
704 int PowellFuncPolyEval(void *p,int n, const double *x, double *fvec, int iflag)
705 {
706 #ifdef BIAS_HAVE_GSL
707  //cast pointer to object to access members, make it threadsafe!
708  PolynomialSolve* ptr = NULL;
709  //ptr = dynamic_cast<PolynomialSolve*>(p);
710  ptr = (PolynomialSolve*)(p);
711  if(ptr != NULL && ptr->PowellCoeff_!=NULL){
712  *fvec=gsl_poly_eval(ptr->PowellCoeff_, ptr->PowellCoeffNum_, *x);
713  return 0;
714  }
715  else{
716  BIASERR("The Coefficients are NULL, something is wrong!");
717  return -2;
718  }
719 #else
720  BIASERR("GSL (Gnu Scientific Library) needed.");
721  return -1;
722 #endif
723 }
724 
725 int PolynomialSolve::NonLinearRefine(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
726  vector<complex<POLYNOMIALSOLVE_TYPE> >& sol)
727 {
728  PowellCoeffNum_=coeff.size();
729  if (PowellCoeff_!=NULL){ delete[] PowellCoeff_; PowellCoeff_=NULL; };
730  PowellCoeff_=new double[PowellCoeffNum_];
731  for (int i=0; i<PowellCoeffNum_; i++) PowellCoeff_[i]=coeff[i];
732  for (unsigned i=0; i<sol.size(); i++){
733  if (imag(sol[i])==0.0){
734  Vector<double> ig(1), re(1);
735  ig[0]=real(sol[i]);
736  if (Powell(PowellFuncPolyEval, (void*)(this), ig, re, 1e-10)==0){
737 #ifdef BIAS_HAVE_GSL
738  GetDebugStream().precision(25);
739  BIASCDOUT(D_PS_NLREFINE, "before refine: "<<ig[0]<<"\tpoly: "
740  <<gsl_poly_eval(PowellCoeff_, PowellCoeffNum_, ig[0])<<endl);
741 #endif
742  sol[i]=(complex<double>(re[0], 0.0));
743 #ifdef BIAS_HAVE_GSL
744  BIASCDOUT(D_PS_NLREFINE, "after refine: "<<re[0]<<"\tpoly: "
745  <<gsl_poly_eval(PowellCoeff_, PowellCoeffNum_, re[0])
746  <<"\tsol: "<<sol[i]<<endl);
747 #endif
748  } else {
749  BIASERR("nonlinear optimization failed for "<<i);
750  }
751  } else {
752  BIASCDOUT(D_PS_NLREFINE, "not refining "<<sol[i]
753  <<", because solution is imaginary "<<endl);
754  }
755  }
756  delete[] PowellCoeff_; PowellCoeff_=NULL;
757  return 0;
758 }
759 
760 int PolynomialSolve::NonLinearRefine(const vector<POLYNOMIALSOLVE_TYPE>& coeff,
761  vector<POLYNOMIALSOLVE_TYPE>& sol)
762 {
763  PowellCoeffNum_=coeff.size();
764  if (PowellCoeff_!=NULL){ delete[] PowellCoeff_; PowellCoeff_=NULL; };
765  PowellCoeff_=new double[PowellCoeffNum_];
766  for (int i=0; i<PowellCoeffNum_; i++) PowellCoeff_[i]=coeff[i];
767  for (unsigned i=0; i<sol.size(); i++){
768  Vector<double> initialvalue(1), resultvalue(1);
769  initialvalue[0] = sol[i];
770  if (Powell(PowellFuncPolyEval,(void*)(this),initialvalue, resultvalue, 1e-15)==0){
771  BIASCDOUT(D_PS_NLREFINE, "residual before refine: "
772  <<PolynomialSolve::EvaluatePolynomial(sol[i], coeff)
773  <<"\troot: "<<setprecision(19)<<sol[i]<<endl);
774  sol[i]=resultvalue[0];
775  BIASCDOUT(D_PS_NLREFINE, "residual after refine: "
776  <<PolynomialSolve::EvaluatePolynomial(sol[i], coeff)
777  <<"\troot: "<<setprecision(19)<<sol[i]<<endl);
778 
779  } else {
780  // BIASERR("nonlinear optimization failed for "<<i);
781  }
782  }
783  delete[] PowellCoeff_; PowellCoeff_=NULL;
784  return 0;
785 }
786 
787 
788 vector<double> values;
789 vector<double> locations;
790 
791 int TheErrorFunction(void *p,int m, int n, const double *x,
792  double *fvec, int iflag) {
793  vector<double> params;
794  for (int i=0; i<n; i++) params.push_back(x[i]);
795 
796  PolynomialSolve PS;
797  for (int j=0; j<m; j++)
798  fvec[j] = values[j] - PS.EvaluatePolynomial(locations[j], params);
799  return 0;
800 }
801 
802 
803 int PolynomialSolve::FitPolynomial(const unsigned int degree,
804  const std::vector<double>& x,
805  const std::vector<double>& y,
806  std::vector<double> &coefficients) {
807  BIASASSERT(x.size()==y.size());
808  coefficients.clear();
809  coefficients.resize(degree+1, 0.0);
810  Matrix<double> A(x.size(), degree+1);
811  Vector<double> B(y.size()), X(degree+1);
812  for (unsigned int row=0; row<x.size(); row++) {
813  const double & xc = x[row];
814  for (unsigned int col=0; col<degree+1; col++) {
815  A[row][col] = 1;
816  for (unsigned int colpower=0; colpower<col; colpower++)
817  A[row][col] *= xc;
818  }
819  B[row] = y[row];
820  }
821 
822 
823  SVD mySVD;
824  int result = mySVD.Solve(A, B, X);
825  if (result!=0) {
826  BIASERR("linear solution failed");
827  return -1;
828  }
829  Vector<double> resultcoeff(degree+1);
830 
831  // optimize numerically unstable linear result
832  values = y;
833  locations = x;
834 
835  if ((result = LevenbergMarquardt(&TheErrorFunction, (void*)(this), x.size(), degree+1,
836  X,resultcoeff,
837  MINPACK_DEF_TOLERANCE))!=0) {
838  BIASERR("Error in Levenberg-Marquardt-Optimization of Polynomial: "<<result);
839  // use linear solution
840  for (unsigned int col=0; col<degree+1; col++) coefficients[col] = X[col];
841  } else {
842  // use these coefficients
843  for (unsigned int col=0; col<degree+1; col++) {
844  coefficients[col] = resultcoeff[col];
845  }
846  }
847  // optimization falied, but linear ok:
848  if (result!=0) return 1;
849  return 0;
850 }
851 
int NonLinearRefine(const std::vector< POLYNOMIALSOLVE_TYPE > &coeff, std::vector< std::complex< POLYNOMIALSOLVE_TYPE > > &sol)
does a non linear refinement using Powel from minpack for real roots (non imaginary) only ...
computes and holds the singular value decomposition of a rectangular (not necessarily quadratic) Matr...
Definition: SVD.hh:92
void CheckCoefficients(std::vector< POLYNOMIALSOLVE_TYPE > &coeff, double eps=DBL_EPSILON)
removes leading zeros in coefficients
Vector< double > Solve(const Vector< double > &y) const
Definition: SVD.cpp:135
int Numeric(const std::vector< POLYNOMIALSOLVE_TYPE > &coeff, std::vector< POLYNOMIALSOLVE_TYPE > &sol)
solves polynomial of arbitrary order n numerically coeff[n]x^n+...+coeff[2]x^2+coeff[1]x+coeff[0]=0 c...
int FitPolynomial(const unsigned int degree, const std::vector< double > &x, const std::vector< double > &y, std::vector< double > &coefficients)
given locations x and measurements y=f(x) approximate f by a polynomial of arbitrary degree and retur...
int Linear(const std::vector< POLYNOMIALSOLVE_TYPE > &coeff, std::vector< POLYNOMIALSOLVE_TYPE > &sol)
solve a polynomial of degree 1 coeff[1]*x+coeff[0]=0 coeff[1] != 0.0 is asserted returns the number o...
int GetNumberOfRealSolutions(const std::vector< POLYNOMIALSOLVE_TYPE > &coeff)
determine number of real solutions of polynomial
int Quadratic(const std::vector< POLYNOMIALSOLVE_TYPE > &coeff, std::vector< POLYNOMIALSOLVE_TYPE > &sol)
solve a polynomial of degree 2 coeff[2]*x^2+coeff[1]*x+coeff[0]=0 coeff[2] != 0.0 is asserted returns...
POLYNOMIALSOLVE_TYPE _GetCoeff(int order, int b, const std::vector< POLYNOMIALSOLVE_TYPE > &sol)
helper function for CalCoefficients
int Solve(const std::vector< std::complex< double > > &coeffs, std::vector< std::complex< double > > &roots, const double eps=1.0e-14)
compute roots of a polynomial using the laguerre method
Definition: Laguerre.cpp:46
base class for solving polynomial equations
POLYNOMIALSOLVE_TYPE EvaluatePolynomial(const POLYNOMIALSOLVE_TYPE x, const std::vector< POLYNOMIALSOLVE_TYPE > &coeff) const
numerically robust way to evaluate a polynomial at position x, uses Horner scheme (same principle as ...
int Cubic(const std::vector< POLYNOMIALSOLVE_TYPE > &coeff, std::vector< POLYNOMIALSOLVE_TYPE > &sol)
solve a polynomial of degree 3 coeff[3]*x^3+coeff[2]*x^2+coeff[1]*x+coeff[0]=0 coeff[3] != 0...
void CalCoefficients(const std::vector< POLYNOMIALSOLVE_TYPE > &sol, std::vector< POLYNOMIALSOLVE_TYPE > &coeff)
inverse function, calculates coefficients from the solutions
class encapsulating a laguerre solver for polynomials
Definition: Laguerre.hh:39
int Quartic(const std::vector< POLYNOMIALSOLVE_TYPE > &coeff, std::vector< POLYNOMIALSOLVE_TYPE > &sol)
solve a polynomial of degree 4 coeff[4]*x^4+coeff[3]*x^3+coeff[2]*x^2+coeff[1]*x+coeff[0]=0 coeff[4] ...
long int LevenbergMarquardt(minpack_funcder_mn fun, void *p, long int m, long int n, Vector< double > &InitialGuess, Vector< double > &Result, double Tolerance)
Solves an overdetermined system f(x) = 0 of m non-linear equations with n parameters using the Levenb...
Definition: Minpack.cpp:97
int Analytic(const std::vector< POLYNOMIALSOLVE_TYPE > &coeff, std::vector< POLYNOMIALSOLVE_TYPE > &sol)
solves polynomial of arbitrary order n&lt;=4 analytically coeff[n]x^n+...+coeff[2]x^2+coeff[1]x+coeff[0]...
bool Equal(const T left, const T right, const T eps)
comparison function for floating point values See http://www.boost.org/libs/test/doc/components/test_...
int Solve(const std::vector< POLYNOMIALSOLVE_TYPE > &coeff, std::vector< POLYNOMIALSOLVE_TYPE > &sol)
solve polynomial of arbitrary order n coeff[n]x^n+...+coeff[2]x^2+coeff[1]x+coeff[0]=0 coeff[n]!=0...
long int Powell(minpack_func_nn fun, void *p, Vector< double > &InitialGuess, Vector< double > &Result, double Tolerance)
Solve a system f(x) = 0 of n non-linear equations with n unknowns using the Powell hybrid method...
Definition: Minpack.cpp:35