core/vnl/algo/vnl_rpoly_roots.cxx
Go to the documentation of this file.
00001 // This is core/vnl/algo/vnl_rpoly_roots.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 //
00008 // \author Andrew W. Fitzgibbon, Oxford RRG
00009 // \date   06 Aug 96
00010 //
00011 //-----------------------------------------------------------------------------
00012 
00013 #include "vnl_rpoly_roots.h"
00014 
00015 #include <vcl_cmath.h> // for fabs()
00016 #include <vcl_iostream.h>
00017 #include <vcl_complex.h>
00018 #include <vnl/algo/vnl_netlib.h> // rpoly_()
00019 #include <vnl/vnl_real_polynomial.h>
00020 
00021 // - The constructor calculates the roots.  This is the most efficient interface
00022 // as all the result variables are initialized to the correct size.
00023 // The polynomial is $ a[0] x^d + a[1] x^{d-1} + \cdots + a[d] = 0 $.
00024 // Note that if the routine fails, not all roots will be found.  In this case,
00025 // the "realroots" and "roots" functions will return fewer than n roots.
00026 vnl_rpoly_roots::vnl_rpoly_roots(const vnl_vector<double>& a)
00027   : coeffs_(a), r_(coeffs_.size()-1), i_(coeffs_.size()-1)
00028 {
00029   // fsm : if the coefficients are NaNs then rpoly_ gets stuck in an
00030   // infinite loop. of course, the caller shouldn't pass in NaNs, but
00031   // it would be nice to get an error message instead of hanging.
00032   a.assert_finite();
00033 
00034   compute();
00035 }
00036 
00037 vnl_rpoly_roots::vnl_rpoly_roots(const vnl_real_polynomial& poly)
00038   : coeffs_(poly.coefficients()), r_(poly.degree()), i_(poly.degree())
00039 {
00040   poly.coefficients().assert_finite();
00041 
00042   compute();
00043 }
00044 
00045 // - Complex vector of all roots.
00046 vnl_vector<vcl_complex<double> > vnl_rpoly_roots::roots() const
00047 {
00048   vnl_vector<vcl_complex<double> > ret(num_roots_found_);
00049   for (int i = 0; i < num_roots_found_; ++i)
00050     ret[i] = vcl_complex<double>(r_[i], i_[i]);
00051   return ret;
00052 }
00053 
00054 // - Return real roots only.  Roots are real if the absolute value
00055 // of their imaginary part is less than the optional argument TOL.
00056 // TOL defaults to 1e-12 [untested]
00057 vnl_vector<double> vnl_rpoly_roots::realroots(double tol) const
00058 {
00059   int c = 0;
00060   for (int i = 0; i < num_roots_found_; ++i)
00061     if (vcl_fabs(i_[i]) < tol)
00062       ++c;
00063 
00064   vnl_vector<double> ret(c);
00065   c = 0;
00066   {for (int i = 0; i < num_roots_found_; ++i)
00067     if (vcl_fabs(i_[i]) < tol)
00068       ret[c++] = r_[i];}
00069 
00070   return ret;
00071 }
00072 
00073 //: Compute roots using Jenkins-Traub algorithm.
00074 // Calls rpoly and interprets failure codes.
00075 bool vnl_rpoly_roots::compute()
00076 {
00077   long fail = 0;
00078   long n = coeffs_.size() - 1;
00079   v3p_netlib_rpoly_global_t rpoly_global;
00080   v3p_netlib_rpoly_(coeffs_.data_block(), &n,
00081                     r_.data_block(), i_.data_block(), &fail, &rpoly_global);
00082 
00083   if (!fail) {
00084     num_roots_found_ = n;
00085     return true;
00086   }
00087 
00088   num_roots_found_ = n;
00089 
00090   if (coeffs_[0] == 0.0)
00091     vcl_cerr << "vnl_rpoly_roots: Leading coefficient is zero.  Not allowed.\n";
00092   else
00093     vcl_cerr << "vnl_rpoly_roots: Calculation failed, only " << n << " roots found\n";
00094 
00095   return false;
00096 }