core/vnl/algo/vnl_rnpoly_solve.cxx

Go to the documentation of this file.
00001 // This is core/vnl/algo/vnl_rnpoly_solve.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 #include "vnl_rnpoly_solve.h"
00008 
00009 #include <vcl_cmath.h>
00010 #include <vcl_cassert.h>
00011 #ifdef DEBUG
00012 #include <vcl_iostream.h>
00013 #include <vcl_fstream.h>
00014 #endif
00015 
00016 static unsigned int dim_ = 0; // dimension of the problem
00017 static unsigned int max_deg_ = 0; // maximal degree
00018 static unsigned int max_nterms_ = 0; // maximal number of terms
00019 
00020 //: This is a local implementation of a minimal "complex number" class, for internal use only
00021 class vnl_rnpoly_solve_cmplx
00022 {
00023  public:
00024   double R;
00025   double C;
00026   vnl_rnpoly_solve_cmplx(double a=0, double b=0) : R(a), C(b) {}
00027   inline double norm() const { return R*R+C*C; }
00028   inline vnl_rnpoly_solve_cmplx operator-() const
00029   { return vnl_rnpoly_solve_cmplx(-R, -C); }
00030   inline vnl_rnpoly_solve_cmplx operator+(vnl_rnpoly_solve_cmplx const& Y) const
00031   { return vnl_rnpoly_solve_cmplx(R+Y.R, C+Y.C); }
00032   inline vnl_rnpoly_solve_cmplx operator-(vnl_rnpoly_solve_cmplx const& Y) const
00033   { return vnl_rnpoly_solve_cmplx(R-Y.R, C-Y.C); }
00034   inline vnl_rnpoly_solve_cmplx& operator+=(vnl_rnpoly_solve_cmplx const& Y)
00035   { R+=Y.R; C+=Y.C; return *this; }
00036   inline vnl_rnpoly_solve_cmplx& operator-=(vnl_rnpoly_solve_cmplx const& Y)
00037   { R-=Y.R; C-=Y.C; return *this; }
00038   inline vnl_rnpoly_solve_cmplx operator*(vnl_rnpoly_solve_cmplx const& Y) const
00039   { return vnl_rnpoly_solve_cmplx(R*Y.R-C*Y.C, R*Y.C+C*Y.R); }
00040   inline vnl_rnpoly_solve_cmplx operator/(vnl_rnpoly_solve_cmplx const& Y) const
00041   { double N=1.0/Y.norm(); return vnl_rnpoly_solve_cmplx((R*Y.R+C*Y.C)*N, (C*Y.R-R*Y.C)*N); }
00042   inline vnl_rnpoly_solve_cmplx operator*(double T) const
00043   { return vnl_rnpoly_solve_cmplx(R*T, C*T); }
00044   inline vnl_rnpoly_solve_cmplx& operator*=(double T)
00045   { R*=T; C*=T; return *this; }
00046   inline vnl_rnpoly_solve_cmplx& operator*=(vnl_rnpoly_solve_cmplx const& Y)
00047   { double r=R*Y.R-C*Y.C; C=R*Y.C+C*Y.R; R=r; return *this; }
00048   inline vnl_rnpoly_solve_cmplx& operator/=(vnl_rnpoly_solve_cmplx const& Y)
00049   { return *this = operator/(Y); }
00050 };
00051 
00052 static const double twopi = 6.2831853071795864769;
00053 
00054 static const double epsilonB  = 2.e-03;
00055 static const vnl_rnpoly_solve_cmplx  epsilonZ  = vnl_rnpoly_solve_cmplx(1.e-04,1.e-04);
00056 static const double final_eps = 1.e-10;
00057 static const double stepinit  = 1.e-02;
00058 
00059 
00060 vcl_vector<vnl_vector<double>*> vnl_rnpoly_solve::realroots(double tol)
00061 {
00062   tol *= tol; // squared tolerance
00063   vcl_vector<vnl_vector<double>*> rr;
00064   vcl_vector<vnl_vector<double>*>::iterator rp = r_.begin(), ip = i_.begin();
00065   for (; rp != r_.end() && ip != i_.end(); ++rp, ++ip)
00066     if ((*ip)->squared_magnitude() < tol)
00067       rr.push_back(*rp);
00068 
00069   return rr;
00070 }
00071 
00072 
00073 //------------------------- INPTBR ---------------------------
00074 //: Initialize random variables
00075 // This will initialize the random variables which are used
00076 // to preturb the starting point so as to have measure zero
00077 // probability that we will start at a singular point.
00078 static void inptbr(vcl_vector<vnl_rnpoly_solve_cmplx>& p, vcl_vector<vnl_rnpoly_solve_cmplx>& q)
00079 {
00080   vnl_rnpoly_solve_cmplx pp[10],qq[10];
00081 
00082   pp[0] = vnl_rnpoly_solve_cmplx(.12324754231,  .76253746298);
00083   pp[1] = vnl_rnpoly_solve_cmplx(.93857838950,  -.99375892810);
00084   pp[2] = vnl_rnpoly_solve_cmplx(-.23467908356, .39383930009);
00085   pp[3] = vnl_rnpoly_solve_cmplx(.83542556622,  -.10192888288);
00086   pp[4] = vnl_rnpoly_solve_cmplx(-.55763522521, -.83729899911);
00087   pp[5] = vnl_rnpoly_solve_cmplx(-.78348738738, -.10578234903);
00088   pp[6] = vnl_rnpoly_solve_cmplx(.03938347346,  .04825184716);
00089   pp[7] = vnl_rnpoly_solve_cmplx(-.43428734331, .93836289418);
00090   pp[8] = vnl_rnpoly_solve_cmplx(-.99383729993, -.40947822291);
00091   pp[9] = vnl_rnpoly_solve_cmplx(.09383736736,  .26459172298);
00092 
00093   qq[0] = vnl_rnpoly_solve_cmplx(.58720452864,  .01321964722);
00094   qq[1] = vnl_rnpoly_solve_cmplx(.97884134700,  -.14433009712);
00095   qq[2] = vnl_rnpoly_solve_cmplx(.39383737289,  .4154322311);
00096   qq[3] = vnl_rnpoly_solve_cmplx(-.03938376373, -.61253112318);
00097   qq[4] = vnl_rnpoly_solve_cmplx(.39383737388,  -.26454678861);
00098   qq[5] = vnl_rnpoly_solve_cmplx(-.0093837766,  .34447867861);
00099   qq[6] = vnl_rnpoly_solve_cmplx(-.04837366632, .48252736790);
00100   qq[7] = vnl_rnpoly_solve_cmplx(.93725237347,  -.54356527623);
00101   qq[8] = vnl_rnpoly_solve_cmplx(.39373957747,  .65573434564);
00102   qq[9] = vnl_rnpoly_solve_cmplx(-.39380038371, .98903450052);
00103 
00104   p.resize(dim_); q.resize(dim_);
00105   for (unsigned int j=0; j<dim_; ++j) { int jj=j%10; p[j]=pp[jj]; q[j]=qq[jj]; }
00106 }
00107 
00108 //-----------------------------  POWR  -----------------------
00109 //: This returns the complex number y raised to the nth degree
00110 static inline vnl_rnpoly_solve_cmplx powr(int n,vnl_rnpoly_solve_cmplx const& y)
00111 {
00112   vnl_rnpoly_solve_cmplx x(1,0);
00113   if (n>0) while (n--) x *= y;
00114   else     while (n++) x /= y;
00115   return x;
00116 }
00117 
00118 
00119 static void initr(vcl_vector<unsigned int> const& ideg,
00120                   vcl_vector<vnl_rnpoly_solve_cmplx> const& p,
00121                   vcl_vector<vnl_rnpoly_solve_cmplx> const& q,
00122                   vcl_vector<vnl_rnpoly_solve_cmplx>& r,
00123                   vcl_vector<vnl_rnpoly_solve_cmplx>& pdg,
00124                   vcl_vector<vnl_rnpoly_solve_cmplx>& qdg)
00125 {
00126   assert(ideg.size()==dim_);
00127   assert(p.size()==dim_);
00128   assert(q.size()==dim_);
00129   pdg.resize(dim_); qdg.resize(dim_); r.resize(dim_);
00130   for (unsigned int j=0;j<dim_;j++)
00131   {
00132     pdg[j] = powr(ideg[j],p[j]);
00133     qdg[j] = powr(ideg[j],q[j]);
00134     r[j] = q[j] / p[j];
00135   }
00136 }
00137 
00138 
00139 //-------------------------------- DEGREE -------------------------------
00140 //: This will compute the degree of the polynomial based upon the index.
00141 static inline int degree(int index)
00142 {
00143   return (index<0) ? 0 : (index % max_deg_) + 1;
00144 }
00145 
00146 
00147 //-------------------------- FFUNR -------------------------
00148 //: Evaluate the target system component of h.
00149 //  This is the system of equations that we are trying to find the roots.
00150 static void ffunr(vcl_vector<double> const& coeff,
00151                   vcl_vector<int> const& polyn,
00152                   vcl_vector<unsigned int> const& terms,
00153                   vcl_vector<vnl_rnpoly_solve_cmplx> const& x,
00154                   vcl_vector<vnl_rnpoly_solve_cmplx>& pows,
00155                   vcl_vector<vnl_rnpoly_solve_cmplx>& f,
00156                   vcl_vector<vnl_rnpoly_solve_cmplx>& df)
00157 {
00158   assert(terms.size()==dim_);
00159   assert(x.size()==dim_);
00160   // Compute all possible powers for each variable
00161   pows.resize(max_deg_*dim_);
00162   for (unsigned int i=0;i<dim_;i++) // for all variables
00163   {
00164     int index = max_deg_*i;
00165     pows[index]=x[i];
00166     for (unsigned int j=1;j<max_deg_;++j,++index) // for all powers
00167       pows[index+1]= pows[index] * x[i];
00168   }
00169 
00170   // Initialize the new arrays
00171   for (unsigned int i=0; i<dim_; ++i)
00172   {
00173     f[i]=vnl_rnpoly_solve_cmplx(0,0);
00174     for (unsigned int j=0;j<dim_;j++)
00175       df[i*dim_+j]=vnl_rnpoly_solve_cmplx(0,0);
00176   }
00177 
00178   for (unsigned int i=0; i<dim_; ++i) // Across equations
00179     for (unsigned int j=0; j<terms[i]; ++j) // Across terms
00180     {
00181       vnl_rnpoly_solve_cmplx tmp(1,0);
00182       for (unsigned int k=0; k<dim_; ++k) // For each variable
00183       {
00184         int index=polyn[i*dim_*max_nterms_+j*dim_+k];
00185         if (index>=0)
00186           tmp *= pows[index];
00187       }
00188       f[i] += tmp * coeff[i*max_nterms_+j];
00189     }
00190 
00191   // Compute the Derivative!
00192   for (int i=dim_-1;i>=0;i--) // Over equations
00193     for (int l=dim_-1;l>=0;l--) // With respect to each variable
00194     {
00195       vnl_rnpoly_solve_cmplx& df_il = df[i*dim_+l];
00196       for (int j=terms[i]-1;j>=0;j--) // Over terms in each equation
00197         if (polyn[i*dim_*max_nterms_+j*dim_+l]>=0) // if 0 deg in l, df term is 0
00198         {
00199           vnl_rnpoly_solve_cmplx tmp = vnl_rnpoly_solve_cmplx(1,0);
00200           for (int k=dim_-1;k>=0;k--)        // Over each variable in each term
00201           {
00202             int index=polyn[i*dim_*max_nterms_+j*dim_+k];
00203             if (index>=0)
00204             {
00205               if (k==l)
00206               {
00207                 int deg = degree(index);
00208                 if (deg > 1)
00209                   tmp *= pows[index-1];
00210                 tmp *= (double)deg;
00211               }
00212               else
00213                 tmp *= pows[index];
00214             }
00215           } // end for k
00216           df_il += tmp * coeff[i*max_nterms_+j];
00217         }
00218     } // end for l
00219 }
00220 
00221 
00222 //--------------------------- GFUNR --------------------------
00223 //: Evaluate starting system component
00224 // Evaluate the starting system component of h from a system
00225 // of equations that we already know the roots. (ex: x^n - 1)
00226 static void gfunr(vcl_vector<unsigned int> const& ideg,
00227                   vcl_vector<vnl_rnpoly_solve_cmplx> const& pdg,
00228                   vcl_vector<vnl_rnpoly_solve_cmplx> const& qdg,
00229                   vcl_vector<vnl_rnpoly_solve_cmplx> const& pows,
00230                   vcl_vector<vnl_rnpoly_solve_cmplx>& g,
00231                   vcl_vector<vnl_rnpoly_solve_cmplx>& dg)
00232 {
00233   assert(ideg.size()==dim_);
00234   assert(g.size()==dim_);
00235   assert(dg.size()==dim_);
00236   vcl_vector<vnl_rnpoly_solve_cmplx> pxdgm1(dim_), pxdg(dim_);
00237 
00238   for (unsigned int j=0; j<dim_; ++j)
00239   {
00240     vnl_rnpoly_solve_cmplx tmp;
00241     if (ideg[j] <= 1)
00242       tmp = vnl_rnpoly_solve_cmplx(1,0);
00243     else
00244       tmp = pows[j*max_deg_+ideg[j]-2];
00245 
00246     pxdgm1[j] = pdg[j] * tmp;
00247   }
00248 
00249   for (unsigned int j=0; j<dim_; ++j)
00250   {
00251     int index = j*max_deg_+ideg[j]-1;
00252     pxdg[j] = pdg[j] * pows[index];
00253   }
00254 
00255   for (unsigned int j=0; j<dim_; ++j)
00256   {
00257     g[j]  = pxdg[j] - qdg[j];
00258     dg[j] = pxdgm1[j] * ideg[j];
00259   }
00260 }
00261 
00262 
00263 //-------------------------- HFUNR --------------------------
00264 //: This is the routine that traces the curve from the gfunr to the f function
00265 //  (i.e. Evaluate the continuation function)
00266 static void hfunr(vcl_vector<unsigned int> const& ideg,
00267                   vcl_vector<vnl_rnpoly_solve_cmplx> const& pdg,
00268                   vcl_vector<vnl_rnpoly_solve_cmplx> const& qdg,
00269                   double t,
00270                   vcl_vector<vnl_rnpoly_solve_cmplx> const& x,
00271                   vcl_vector<vnl_rnpoly_solve_cmplx>& h,
00272                   vcl_vector<vnl_rnpoly_solve_cmplx>& dhx,
00273                   vcl_vector<vnl_rnpoly_solve_cmplx>& dht,
00274                   vcl_vector<int> const& polyn,
00275                   vcl_vector<double> const& coeff,
00276                   vcl_vector<unsigned int> const& terms)
00277 {
00278   assert(ideg.size()==dim_);
00279   assert(terms.size()==dim_);
00280   assert(x.size()==dim_);
00281   assert(h.size()==dim_);
00282   assert(dht.size()==dim_);
00283   assert(dhx.size()==dim_*dim_);
00284   vcl_vector<vnl_rnpoly_solve_cmplx> df(dim_*dim_),dg(dim_),f(dim_),g(dim_);
00285   vcl_vector<vnl_rnpoly_solve_cmplx> pows;  //  powers of variables [dim_ equations] [max_deg_ possible powers]
00286 
00287   ffunr(coeff,polyn,terms,x,pows,f,df);
00288   gfunr(ideg,pdg,qdg,pows,g,dg);
00289   assert(f.size()==dim_);
00290   assert(g.size()==dim_);
00291   assert(dg.size()==dim_);
00292   assert(df.size()==dim_*dim_);
00293 
00294   double onemt=1.0 - t;
00295   for (unsigned int j=0; j<dim_; ++j)
00296   {
00297     for (unsigned int i=0; i<dim_; ++i)
00298       dhx[j*dim_+i] = df[j*dim_+i] * t;
00299 
00300     dhx[j*dim_+j] += dg[j]*onemt;
00301     dht[j] = f[j] - g[j];
00302     h[j] = f[j] * t + g[j] * onemt;
00303   }
00304 }
00305 
00306 
00307 //------------------------ LU DECOMPOSITION --------------------------
00308 //: This performs LU decomposition on a matrix.
00309 static int ludcmp(vcl_vector<vnl_rnpoly_solve_cmplx>& a, vcl_vector<int>& indx)
00310 {
00311   vcl_vector<double> vv(dim_);
00312 
00313   // Loop over rows to get the implicit scaling information
00314   for (unsigned int i=0; i<dim_; ++i)
00315   {
00316     double big = 0.0;
00317     for (unsigned int j=0; j<dim_; ++j)
00318     {
00319       double temp = a[i*dim_+j].norm();
00320       if (temp > big) big = temp;
00321     }
00322     if (big == 0.0) return 1;
00323     vv[i]=1.0/vcl_sqrt(big);
00324   }
00325 
00326   // This is the loop over columns of Crout's method
00327   for (unsigned int j=0; j<dim_; ++j)
00328   {
00329     for (unsigned int i=0; i<j; ++i)
00330       for (unsigned int k=0; k<i; ++k)
00331         a[i*dim_+j] -= a[i*dim_+k] * a[k*dim_+j];
00332 
00333     // Initialize for the search for largest pivot element
00334     double big = 0.0;
00335     unsigned int imax = 0;
00336 
00337     for (unsigned int i=j; i<dim_; ++i)
00338     {
00339       for (unsigned int k=0; k<j; ++k)
00340         a[i*dim_+j] -= a[i*dim_+k] * a[k*dim_+j];
00341 
00342       // Is the figure of merit for the pivot better than the best so far?
00343       double rdum = vv[i]*a[i*dim_+j].norm();
00344       if (rdum >= big) { big = rdum; imax = i; }
00345     }
00346 
00347     // Do we need to interchange rows?
00348     if (j != imax)
00349     {
00350       // Yes, do so...
00351       for (unsigned int k=0; k<dim_; ++k)
00352       {
00353         vnl_rnpoly_solve_cmplx dum = a[imax*dim_+k];
00354         a[imax*dim_+k] = a[j*dim_+k]; a[j*dim_+k] = dum;
00355       }
00356 
00357       // Also interchange the scale factor
00358       vv[imax]=vv[j];
00359     }
00360     indx[j]=imax;
00361 
00362     vnl_rnpoly_solve_cmplx& ajj = a[j*dim_+j];
00363     if (ajj.norm() == 0.0)
00364       ajj = epsilonZ;
00365 
00366     // Now, finally, divide by the pivot element
00367     if (j+1 != dim_)
00368     {
00369       vnl_rnpoly_solve_cmplx dum = vnl_rnpoly_solve_cmplx(1,0) / ajj;
00370 
00371       // If the pivot element is zero the matrix is singular.
00372       for (unsigned int i=j+1; i<dim_; ++i)
00373         a[i*dim_+j] *= dum;
00374     }
00375   }
00376   return 0;
00377 }
00378 
00379 
00380 // ------------------------- LU Back Substitution -------------------------
00381 static void lubksb(vcl_vector<vnl_rnpoly_solve_cmplx> const& a,
00382                    vcl_vector<int> const& indx,
00383                    vcl_vector<vnl_rnpoly_solve_cmplx> const& bb,
00384                    vcl_vector<vnl_rnpoly_solve_cmplx>& b)
00385 {
00386   int ii=-1;
00387   for (unsigned int k=0; k<dim_; ++k)
00388     b[k] = bb[k];
00389 
00390   for (unsigned int i=0; i<dim_; ++i)
00391   {
00392     int ip = indx[i];
00393     vnl_rnpoly_solve_cmplx sum = b[ip];
00394     b[ip] = b[i];
00395 
00396     if (ii>=0)
00397       for (unsigned int j=ii;j<i;++j)
00398         sum -= a[i*dim_+j] * b[j];
00399     else
00400       // A nonzero element was encountered, so from now on we
00401       // will have to do the sums in the loop above
00402       if (sum.norm() > 0) ii = i;
00403 
00404     b[i] = sum;
00405   }
00406 
00407   // Now do the backsubstitution
00408   for (int i=dim_-1;i>=0;i--)
00409   {
00410     for (unsigned int j=i+1; j<dim_; ++j)
00411       b[i] -= a[i*dim_+j] * b[j];
00412 
00413     b[i] /= a[i*dim_+i];
00414   }
00415 }
00416 
00417 
00418 //-------------------------- LINNR -------------------
00419 //: Solve a complex system of equations by using l-u decomposition and then back substitution.
00420 static int linnr(vcl_vector<vnl_rnpoly_solve_cmplx>& dhx,
00421                  vcl_vector<vnl_rnpoly_solve_cmplx> const& rhs,
00422                  vcl_vector<vnl_rnpoly_solve_cmplx>& resid)
00423 {
00424   vcl_vector<int> irow(dim_);
00425   if (ludcmp(dhx,irow)==1) return 1;
00426   lubksb(dhx,irow,rhs,resid);
00427   return 0;
00428 }
00429 
00430 
00431 //-----------------------  XNORM  --------------------
00432 //: Finds the unit normal of a vector v
00433 static double xnorm(vcl_vector<vnl_rnpoly_solve_cmplx> const& v)
00434 {
00435   assert(v.size()==dim_);
00436   double txnorm=0.0;
00437   for (unsigned int j=0; j<dim_; ++j)
00438     txnorm += vcl_fabs(v[j].R) + vcl_fabs(v[j].C);
00439   return txnorm;
00440 }
00441 
00442 //---------------------- PREDICT ---------------------
00443 //: Predict new x vector using Taylor's Expansion.
00444 static void predict(vcl_vector<unsigned int> const& ideg,
00445                     vcl_vector<vnl_rnpoly_solve_cmplx> const& pdg,
00446                     vcl_vector<vnl_rnpoly_solve_cmplx> const& qdg,
00447                     double step, double& t,
00448                     vcl_vector<vnl_rnpoly_solve_cmplx>& x,
00449                     vcl_vector<int> const& polyn,
00450                     vcl_vector<double> const& coeff,
00451                     vcl_vector<unsigned int> const& terms)
00452 {
00453   assert(ideg.size()==dim_);
00454   assert(terms.size()==dim_);
00455   assert(x.size()==dim_);
00456 
00457   double maxdt =.2; // Maximum change in t for a given step.  If dt is
00458                     // too large, there seems to be greater chance of
00459                     // jumping to another path.  Set this to 1 if you
00460                     // don't care.
00461   vcl_vector<vnl_rnpoly_solve_cmplx> dht(dim_),dhx(dim_*dim_),dz(dim_),h(dim_),rhs(dim_);
00462   // Call the continuation function that we are tracing
00463   hfunr(ideg,pdg,qdg,t,x,h,dhx,dht,polyn,coeff,terms);
00464 
00465   for (unsigned int j=0; j<dim_; ++j)
00466     rhs[j] = - dht[j];
00467 
00468   // Call the function that solves a complex system of equations
00469   if (linnr(dhx,rhs,dz) == 1) return;
00470 
00471   // Find the unit normal of a vector and normalize our step
00472   double factor = step/(1+xnorm(dz));
00473   if (factor>maxdt) factor = maxdt;
00474 
00475   bool tis1=true;
00476   if (t+factor>1) { tis1 = false; factor = 1.0 - t; }
00477 
00478   // Update this path with the predicted next point
00479   for (unsigned int j=0; j<dim_; ++j)
00480     x[j] += dz[j] * factor;
00481 
00482   if (tis1) t += factor;
00483   else      t = 1.0;
00484 }
00485 
00486 
00487 //------------------------- CORRECT --------------------------
00488 //: Correct the predicted point to lie near the actual curve
00489 // Use Newton's Method to do this.
00490 // Returns:
00491 // 0: Converged
00492 // 1: Singular Jacobian
00493 // 2: Didn't converge in 'loop' iterations
00494 // 3: If the magnitude of x > maxroot
00495 static int correct(vcl_vector<unsigned int> const& ideg, int loop, double eps,
00496                    vcl_vector<vnl_rnpoly_solve_cmplx> const& pdg,
00497                    vcl_vector<vnl_rnpoly_solve_cmplx> const& qdg,
00498                    double t,
00499                    vcl_vector<vnl_rnpoly_solve_cmplx>& x,
00500                    vcl_vector<int> const& polyn,
00501                    vcl_vector<double> const& coeff,
00502                    vcl_vector<unsigned int> const& terms)
00503 {
00504   double maxroot= 1000;// Maximum size of root where it is considered heading to infinity
00505   vcl_vector<vnl_rnpoly_solve_cmplx> dhx(dim_*dim_),dht(dim_),h(dim_),resid(dim_);
00506 
00507   assert(ideg.size()==dim_);
00508   assert(terms.size()==dim_);
00509   assert(x.size()==dim_);
00510 
00511   for (int i=0;i<loop;i++)
00512   {
00513     hfunr(ideg,pdg,qdg,t,x,h,dhx,dht,polyn,coeff,terms);
00514 
00515     // If linnr = 1, error
00516     if (linnr(dhx,h,resid)==1) return 1;
00517 
00518     for (unsigned int j=0; j<dim_; ++j)
00519       x[j] -= resid[j];
00520 
00521     double xresid = xnorm(resid);
00522     if (xresid < eps) return 0;
00523     if (xresid > maxroot) return 3;
00524   }
00525   return 2;
00526 }
00527 
00528 
00529 //-------------------------- TRACE ---------------------------
00530 //: This is the continuation routine.
00531 // It will trace a curve from a known point in the complex plane to an unknown
00532 // point in the complex plane.  The new end point is the root
00533 // to a polynomial equation that we are trying to solve.
00534 // It will return the following codes:
00535 //      0: Maximum number of steps exceeded
00536 //      1: Path converged
00537 //      2: Step size became too small
00538 //      3: Path Heading to infinity
00539 //      4: Singular Jacobian on Path
00540 static int trace(vcl_vector<vnl_rnpoly_solve_cmplx>& x,
00541                  vcl_vector<unsigned int> const& ideg,
00542                  vcl_vector<vnl_rnpoly_solve_cmplx> const& pdg,
00543                  vcl_vector<vnl_rnpoly_solve_cmplx> const& qdg,
00544                  vcl_vector<int> const& polyn,
00545                  vcl_vector<double> const& coeff,
00546                  vcl_vector<unsigned int> const& terms)
00547 {
00548   assert(ideg.size()==dim_);
00549   assert(terms.size()==dim_);
00550   assert(x.size()==dim_);
00551 
00552   int maxns=500;  // Maximum number of path steps
00553   int maxit=5;    // Maximum number of iterations to correct a step.
00554                   // For each step, Newton-Raphson is used to correct
00555                   // the step.  This should be at least 3 to improve
00556                   // the chances of convergence. If function is well
00557                   // behaved, fewer than maxit steps will be needed
00558 
00559   double eps=0;                     // epsilon value used in correct
00560   double epsilonS=1.0e-3 * epsilonB;// smallest path step for t>.95
00561   double stepmin=1.0e-5 * stepinit; // Minimum stepsize allowed
00562   double step=stepinit;             // stepsize
00563   double t=0.0;                     // Continuation parameter 0<t<1
00564   double oldt=0.0;                  // The previous t value
00565   vcl_vector<vnl_rnpoly_solve_cmplx> oldx = x; // the previous path value
00566   int nadv=0;
00567 
00568   for (int numstep=0;numstep<maxns;numstep++)
00569   {
00570     // Taylor approximate the next point
00571     predict(ideg,pdg,qdg,step,t,x,polyn,coeff,terms);
00572 
00573     //if (t>1.0) t=1.0;
00574 
00575     if (t > .95)
00576     {
00577       if (eps != epsilonS) step = step/4.0;
00578       eps = epsilonS;
00579     }else
00580       eps = epsilonB;
00581 #ifdef DEBUG
00582     vcl_cout << "t=" << t << vcl_endl;
00583 #endif
00584 
00585     if (t>=.99999)                      // Path converged
00586     {
00587 #ifdef DEBUG
00588       vcl_cout << "path converged\n" << vcl_flush;
00589 #endif
00590       double factor = (1.0-oldt)/(t-oldt);
00591       for (unsigned int j=0; j<dim_; ++j)
00592         x[j] = oldx[j] + (x[j]-oldx[j]) * factor;
00593       t = 1.0;
00594       int cflag=correct(ideg,10*maxit,final_eps,pdg,qdg,t,x, polyn, coeff,terms);
00595       if ((cflag==0) ||(cflag==2))
00596         return 1;       // Final Correction converged
00597       else if (cflag==3)
00598         return 3;       // Heading to infinity
00599       else return 4;    // Singular solution
00600     }
00601 
00602     // Newton's method brings us back to the curve
00603     int cflag=correct(ideg,maxit,eps,pdg,qdg,t,x,polyn, coeff,terms);
00604     if (cflag==0)
00605     {
00606       // Successful step
00607       if ((++nadv)==maxit) { step *= 2; nadv=0; }   // Increase the step size
00608       // Make note of our new location
00609       oldt = t;
00610       oldx = x;
00611     }
00612     else
00613     {
00614       nadv=0;
00615       step /= 2.0;
00616 
00617       if (cflag==3) return 3;           // Path heading to infinity
00618       if (step<stepmin) return 2;       // Path failed StepSizeMin exceeded
00619 
00620       // Reset the values since we stepped to far, and try again
00621       t = oldt;
00622       x = oldx;
00623     }
00624   }// end of the loop numstep
00625 
00626   return 0;
00627 }
00628 
00629 
00630 //-------------------------- STRPTR ---------------------------
00631 //: This will find a starting point on the 'g' function circle.
00632 // The new point to start tracing is stored in the x array.
00633 static void strptr(vcl_vector<unsigned int>& icount,
00634                    vcl_vector<unsigned int> const& ideg,
00635                    vcl_vector<vnl_rnpoly_solve_cmplx> const& r,
00636                    vcl_vector<vnl_rnpoly_solve_cmplx>& x)
00637 {
00638   assert(ideg.size()==dim_);
00639   assert(r.size()==dim_);
00640   x.resize(dim_);
00641 
00642   for (unsigned int i=0; i<dim_; ++i)
00643     if (icount[i] >= ideg[i]) icount[i] = 1;
00644     else                    { icount[i]++; break; }
00645 
00646   for (unsigned int j=0; j<dim_; ++j)
00647   {
00648     double angle = twopi / ideg[j] * icount[j];
00649     x[j] = r[j] * vnl_rnpoly_solve_cmplx (vcl_cos(angle), vcl_sin(angle));
00650   }
00651 }
00652 
00653 
00654 static vcl_vector<vcl_vector<vnl_rnpoly_solve_cmplx> >
00655 Perform_Distributed_Task(vcl_vector<unsigned int> const& ideg,
00656                          vcl_vector<unsigned int> const& terms,
00657                          vcl_vector<int> const& polyn,
00658                          vcl_vector<double> const& coeff)
00659 {
00660   assert(ideg.size()==dim_);
00661 
00662   vcl_vector<vcl_vector<vnl_rnpoly_solve_cmplx> > sols;
00663   vcl_vector<vnl_rnpoly_solve_cmplx> pdg, qdg, p, q, r, x;
00664   vcl_vector<unsigned int> icount(dim_,1); icount[0]=0;
00665   bool solflag; // flag used to remember if a root is found
00666 #ifdef DEBUG
00667   char const* FILENAM = "/tmp/cont.results";
00668   vcl_ofstream F(FILENAM);
00669   if (!F)
00670   {
00671     vcl_cerr<<"could not open "<<FILENAM<<" for writing\nplease erase old file first\n";
00672     F = vcl_cerr;
00673   }
00674   else
00675     vcl_cerr << "Writing to " << FILENAM << '\n';
00676 #endif
00677   // Initialize some variables
00678   inptbr(p,q);
00679   initr(ideg,p,q,r,pdg,qdg);
00680 
00681   // int Psize = 2*dim_*sizeof(double);
00682   int totdegree = 1;            // Total degree of the system
00683   for (unsigned int j=0;j<dim_;j++)  totdegree *= ideg[j];
00684 
00685   // *************  Send initial information ****************
00686   //Initialize(dim_,maxns,maxdt,maxit,maxroot,
00687   //           terms,ideg,pdg,qdg,coeff,polyn);
00688   while ((totdegree--) > 0)
00689   {
00690     // Compute path to trace
00691     strptr(icount,ideg,r,x);
00692 
00693     // Tell the client which path you want it to trace
00694     solflag = 1 == trace(x,ideg,pdg,qdg,polyn,coeff,terms);
00695     // Save the solution for future reference
00696     if (solflag)
00697     {
00698 #ifdef DEBUG
00699       for (unsigned int i=0; i<dim_; ++i)
00700         F << '<' << x[dim_-i-1].R << ' ' << x[dim_-i-1].C << '>';
00701       F << vcl_endl;
00702 #endif
00703       sols.push_back(x);
00704     }
00705 #ifdef DEBUG
00706     // print something out for each root
00707     if (solflag) vcl_cout << '.';
00708     else         vcl_cout << '*';
00709     vcl_cout.flush();
00710 #endif
00711   }
00712 
00713 #ifdef DEBUG
00714   vcl_cout<< vcl_endl;
00715 #endif
00716 
00717   return sols;
00718 }
00719 
00720 
00721 //----------------------- READ INPUT ----------------------
00722 //: This will read the input polynomials from a data file.
00723 void vnl_rnpoly_solve::Read_Input(vcl_vector<unsigned int>& ideg,
00724                                   vcl_vector<unsigned int>& terms,
00725                                   vcl_vector<int>& polyn,
00726                                   vcl_vector<double>& coeff)
00727 {
00728   // Read the number of equations
00729   dim_ = ps_.size();
00730 
00731   ideg.resize(dim_); terms.resize(dim_);
00732   // Start reading in the array values
00733   max_deg_=0;
00734   max_nterms_=0;
00735   for (unsigned int i=0;i<dim_;i++)
00736   {
00737     ideg[i] = ps_[i]->ideg_;
00738     terms[i] = ps_[i]->nterms_;
00739     if (ideg[i] > max_deg_)
00740       max_deg_ = ideg[i];
00741     if (terms[i] > max_nterms_)
00742       max_nterms_ = terms[i];
00743   }
00744   coeff.resize(dim_*max_nterms_);
00745   polyn.resize(dim_*max_nterms_*dim_);
00746   for (unsigned int i=0;i<dim_;i++)
00747   {
00748     for (unsigned int k=0;k<terms[i];k++)
00749     {
00750       coeff[i*max_nterms_+k] = ps_[i]->coeffs_(k);
00751       for (unsigned int j=0;j<dim_;j++)
00752       {
00753         int deg = ps_[i]->polyn_(k,j);
00754         polyn[i*dim_*max_nterms_+k*dim_+j] = deg ? int(j*max_deg_)+deg-1 : -1;
00755       }
00756     }
00757   }
00758 }
00759 
00760 
00761 vnl_rnpoly_solve::~vnl_rnpoly_solve()
00762 {
00763   while (r_.size() > 0) { delete r_.back(); r_.pop_back(); }
00764   while (i_.size() > 0) { delete i_.back(); i_.pop_back(); }
00765 }
00766 
00767 bool vnl_rnpoly_solve::compute()
00768 {
00769   vcl_vector<unsigned int> ideg, terms;
00770   vcl_vector<int> polyn;
00771   vcl_vector<double> coeff;
00772 
00773   Read_Input(ideg,terms,polyn,coeff); // returns number of equations
00774   assert(ideg.size()==dim_);
00775   assert(terms.size()==dim_);
00776   assert(polyn.size()==dim_*max_nterms_*dim_);
00777   assert(coeff.size()==dim_*max_nterms_);
00778 
00779   int totdegree = 1;
00780   for (unsigned int j=0; j<dim_; ++j) totdegree *= ideg[j];
00781 
00782   vcl_vector<vcl_vector<vnl_rnpoly_solve_cmplx> > ans = Perform_Distributed_Task(ideg,terms,polyn,coeff);
00783 
00784   // Print out the answers
00785   vnl_vector<double> * rp, *ip;
00786 #ifdef DEBUG
00787   vcl_cout << "Total degree: " << totdegree << vcl_endl
00788            << "# solutions : " << ans.size() << vcl_endl;
00789 #endif
00790   for (unsigned int i=0; i<ans.size(); ++i)
00791   {
00792     assert(ans[i].size()==dim_);
00793     rp=new vnl_vector<double>(dim_); r_.push_back(rp);
00794     ip=new vnl_vector<double>(dim_); i_.push_back(ip);
00795     for (unsigned int j=0; j<dim_; ++j)
00796     {
00797 #ifdef DEBUG
00798       vcl_cout << ans[i][j].R << " + j " << ans[i][j].C << vcl_endl;
00799 #endif
00800       (*rp)[j]=ans[i][j].R; (*ip)[j]=ans[i][j].C;
00801     }
00802 #ifdef DEBUG
00803     vcl_cout<< vcl_endl;
00804 #endif
00805   }
00806   return true;
00807 }

Generated on Fri Nov 21 05:06:12 2008 for core/vnl by  doxygen 1.5.1