vnl_rnpoly_solve.cxx
Go to the documentation of this file.
1 // This is core/vnl/algo/vnl_rnpoly_solve.cxx
2 //:
3 // \file
4 #include <cmath>
5 #include <cassert>
6 #include <iostream>
8 #include <vnl/vnl_math.h>
9 
10 #ifdef DEBUG
11 #endif
12 
13 static unsigned int dim_ = 0; // dimension of the problem
14 static unsigned int max_deg_ = 0; // maximal degree
15 static unsigned int max_nterms_ = 0; // maximal number of terms
16 
17 //: This is a local implementation of a minimal "complex number" class, for internal use only
19 {
20  public:
21  double R;
22  double C;
23  vnl_rnpoly_solve_cmplx(double a=0, double b=0) : R(a), C(b) {}
24  inline double norm() const { return R*R+C*C; }
26  { return {-R, -C}; }
28  { return {R+Y.R, C+Y.C}; }
30  { return {R-Y.R, C-Y.C}; }
32  { R+=Y.R; C+=Y.C; return *this; }
34  { R-=Y.R; C-=Y.C; return *this; }
36  { return {R*Y.R-C*Y.C, R*Y.C+C*Y.R}; }
38  { double N=1.0/Y.norm(); return {(R*Y.R+C*Y.C)*N, (C*Y.R-R*Y.C)*N}; }
39  inline vnl_rnpoly_solve_cmplx operator*(double T) const
40  { return {R*T, C*T}; }
42  { R*=T; C*=T; return *this; }
44  { double r=R*Y.R-C*Y.C; C=R*Y.C+C*Y.R; R=r; return *this; }
46  { return *this = operator/(Y); }
47 };
48 
49 static const double twopi = vnl_math::twopi;
50 
51 static const double epsilonB = 2.e-03;
52 static const vnl_rnpoly_solve_cmplx epsilonZ = vnl_rnpoly_solve_cmplx(1.e-04,1.e-04);
53 static const double final_eps = 1.e-10;
54 static const double stepinit = 1.e-02;
55 
56 
57 std::vector<vnl_vector<double>*> vnl_rnpoly_solve::realroots(double tol)
58 {
59  tol *= tol; // squared tolerance
60  std::vector<vnl_vector<double>*> rr;
61  auto rp = r_.begin(), ip = i_.begin();
62  for (; rp != r_.end() && ip != i_.end(); ++rp, ++ip)
63  if ((*ip)->squared_magnitude() < tol)
64  rr.push_back(*rp);
65 
66  return rr;
67 }
68 
69 
70 //------------------------- INPTBR ---------------------------
71 //: Initialize random variables
72 // This will initialize the random variables which are used
73 // to perturb the starting point so as to have measure zero
74 // probability that we will start at a singular point.
75 static void inptbr(std::vector<vnl_rnpoly_solve_cmplx>& p, std::vector<vnl_rnpoly_solve_cmplx>& q)
76 {
77  vnl_rnpoly_solve_cmplx pp[10],qq[10];
78 
79  pp[0] = vnl_rnpoly_solve_cmplx(.12324754231, .76253746298);
80  pp[1] = vnl_rnpoly_solve_cmplx(.93857838950, -.99375892810);
81  pp[2] = vnl_rnpoly_solve_cmplx(-.23467908356, .39383930009);
82  pp[3] = vnl_rnpoly_solve_cmplx(.83542556622, -.10192888288);
83  pp[4] = vnl_rnpoly_solve_cmplx(-.55763522521, -.83729899911);
84  pp[5] = vnl_rnpoly_solve_cmplx(-.78348738738, -.10578234903);
85  pp[6] = vnl_rnpoly_solve_cmplx(.03938347346, .04825184716);
86  pp[7] = vnl_rnpoly_solve_cmplx(-.43428734331, .93836289418);
87  pp[8] = vnl_rnpoly_solve_cmplx(-.99383729993, -.40947822291);
88  pp[9] = vnl_rnpoly_solve_cmplx(.09383736736, .26459172298);
89 
90  qq[0] = vnl_rnpoly_solve_cmplx(.58720452864, .01321964722);
91  qq[1] = vnl_rnpoly_solve_cmplx(.97884134700, -.14433009712);
92  qq[2] = vnl_rnpoly_solve_cmplx(.39383737289, .4154322311);
93  qq[3] = vnl_rnpoly_solve_cmplx(-.03938376373, -.61253112318);
94  qq[4] = vnl_rnpoly_solve_cmplx(.39383737388, -.26454678861);
95  qq[5] = vnl_rnpoly_solve_cmplx(-.0093837766, .34447867861);
96  qq[6] = vnl_rnpoly_solve_cmplx(-.04837366632, .48252736790);
97  qq[7] = vnl_rnpoly_solve_cmplx(.93725237347, -.54356527623);
98  qq[8] = vnl_rnpoly_solve_cmplx(.39373957747, .65573434564);
99  qq[9] = vnl_rnpoly_solve_cmplx(-.39380038371, .98903450052);
100 
101  p.resize(dim_); q.resize(dim_);
102  for (unsigned int j=0; j<dim_; ++j) { int jj=j%10; p[j]=pp[jj]; q[j]=qq[jj]; }
103 }
104 
105 //----------------------------- POWR -----------------------
106 //: This returns the complex number y raised to the nth degree
107 static inline vnl_rnpoly_solve_cmplx powr(int n,vnl_rnpoly_solve_cmplx const& y)
108 {
109  vnl_rnpoly_solve_cmplx x(1,0);
110  if (n>0) while (n--) x *= y;
111  else while (n++) x /= y;
112  return x;
113 }
114 
115 
116 static void initr(std::vector<unsigned int> const& ideg,
117  std::vector<vnl_rnpoly_solve_cmplx> const& p,
118  std::vector<vnl_rnpoly_solve_cmplx> const& q,
119  std::vector<vnl_rnpoly_solve_cmplx>& r,
120  std::vector<vnl_rnpoly_solve_cmplx>& pdg,
121  std::vector<vnl_rnpoly_solve_cmplx>& qdg)
122 {
123  assert(ideg.size()==dim_);
124  assert(p.size()==dim_);
125  assert(q.size()==dim_);
126  pdg.resize(dim_); qdg.resize(dim_); r.resize(dim_);
127  for (unsigned int j=0;j<dim_;j++)
128  {
129  pdg[j] = powr(ideg[j],p[j]);
130  qdg[j] = powr(ideg[j],q[j]);
131  r[j] = q[j] / p[j];
132  }
133 }
134 
135 
136 //-------------------------------- DEGREE -------------------------------
137 //: This will compute the degree of the polynomial based upon the index.
138 static inline int degree(int index)
139 {
140  return (index<0) ? 0 : (index % max_deg_) + 1;
141 }
142 
143 
144 //-------------------------- FFUNR -------------------------
145 //: Evaluate the target system component of h.
146 // This is the system of equations that we are trying to find the roots.
147 static void ffunr(std::vector<double> const& coeff,
148  std::vector<int> const& polyn,
149  std::vector<unsigned int> const& terms,
150  std::vector<vnl_rnpoly_solve_cmplx> const& x,
151  std::vector<vnl_rnpoly_solve_cmplx>& pows,
152  std::vector<vnl_rnpoly_solve_cmplx>& f,
153  std::vector<vnl_rnpoly_solve_cmplx>& df)
154 {
155  assert(terms.size()==dim_);
156  assert(x.size()==dim_);
157  // Compute all possible powers for each variable
158  pows.resize(max_deg_*dim_);
159  for (unsigned int i=0;i<dim_;i++) // for all variables
160  {
161  int index = max_deg_*i;
162  pows[index]=x[i];
163  for (unsigned int j=1;j<max_deg_;++j,++index) // for all powers
164  pows[index+1]= pows[index] * x[i];
165  }
166 
167  // Initialize the new arrays
168  for (unsigned int i=0; i<dim_; ++i)
169  {
170  f[i]=vnl_rnpoly_solve_cmplx(0,0);
171  for (unsigned int j=0;j<dim_;j++)
172  df[i*dim_+j]=vnl_rnpoly_solve_cmplx(0,0);
173  }
174 
175  for (unsigned int i=0; i<dim_; ++i) // Across equations
176  for (unsigned int j=0; j<terms[i]; ++j) // Across terms
177  {
178  vnl_rnpoly_solve_cmplx tmp(1,0);
179  for (unsigned int k=0; k<dim_; ++k) // For each variable
180  {
181  int index=polyn[i*dim_*max_nterms_+j*dim_+k];
182  if (index>=0)
183  tmp *= pows[index];
184  }
185  f[i] += tmp * coeff[i*max_nterms_+j];
186  }
187 
188  // Compute the Derivative!
189  for (int i=dim_-1;i>=0;i--) // Over equations
190  for (int l=dim_-1;l>=0;l--) // With respect to each variable
191  {
192  vnl_rnpoly_solve_cmplx& df_il = df[i*dim_+l];
193  for (int j=terms[i]-1;j>=0;j--) // Over terms in each equation
194  if (polyn[i*dim_*max_nterms_+j*dim_+l]>=0) // if 0 deg in l, df term is 0
195  {
197  for (int k=dim_-1;k>=0;k--) // Over each variable in each term
198  {
199  int index=polyn[i*dim_*max_nterms_+j*dim_+k];
200  if (index>=0)
201  {
202  if (k==l)
203  {
204  int deg = degree(index);
205  if (deg > 1)
206  tmp *= pows[index-1];
207  tmp *= (double)deg;
208  }
209  else
210  tmp *= pows[index];
211  }
212  } // end for k
213  df_il += tmp * coeff[i*max_nterms_+j];
214  }
215  } // end for l
216 }
217 
218 
219 //--------------------------- GFUNR --------------------------
220 //: Evaluate starting system component
221 // Evaluate the starting system component of h from a system
222 // of equations that we already know the roots. (ex: x^n - 1)
223 static void gfunr(std::vector<unsigned int> const& ideg,
224  std::vector<vnl_rnpoly_solve_cmplx> const& pdg,
225  std::vector<vnl_rnpoly_solve_cmplx> const& qdg,
226  std::vector<vnl_rnpoly_solve_cmplx> const& pows,
227  std::vector<vnl_rnpoly_solve_cmplx>& g,
228  std::vector<vnl_rnpoly_solve_cmplx>& dg)
229 {
230  assert(ideg.size()==dim_);
231  assert(g.size()==dim_);
232  assert(dg.size()==dim_);
233  std::vector<vnl_rnpoly_solve_cmplx> pxdgm1(dim_), pxdg(dim_);
234 
235  for (unsigned int j=0; j<dim_; ++j)
236  {
238  if (ideg[j] <= 1)
239  tmp = vnl_rnpoly_solve_cmplx(1,0);
240  else
241  tmp = pows[j*max_deg_+ideg[j]-2];
242 
243  pxdgm1[j] = pdg[j] * tmp;
244  }
245 
246  for (unsigned int j=0; j<dim_; ++j)
247  {
248  int index = j*max_deg_+ideg[j]-1;
249  pxdg[j] = pdg[j] * pows[index];
250  }
251 
252  for (unsigned int j=0; j<dim_; ++j)
253  {
254  g[j] = pxdg[j] - qdg[j];
255  dg[j] = pxdgm1[j] * ideg[j];
256  }
257 }
258 
259 
260 //-------------------------- HFUNR --------------------------
261 //: This is the routine that traces the curve from the gfunr to the f function
262 // (i.e. Evaluate the continuation function)
263 static void hfunr(std::vector<unsigned int> const& ideg,
264  std::vector<vnl_rnpoly_solve_cmplx> const& pdg,
265  std::vector<vnl_rnpoly_solve_cmplx> const& qdg,
266  double t,
267  std::vector<vnl_rnpoly_solve_cmplx> const& x,
268  std::vector<vnl_rnpoly_solve_cmplx>& h,
269  std::vector<vnl_rnpoly_solve_cmplx>& dhx,
270  std::vector<vnl_rnpoly_solve_cmplx>& dht,
271  std::vector<int> const& polyn,
272  std::vector<double> const& coeff,
273  std::vector<unsigned int> const& terms)
274 {
275  assert(ideg.size()==dim_);
276  assert(terms.size()==dim_);
277  assert(x.size()==dim_);
278  assert(h.size()==dim_);
279  assert(dht.size()==dim_);
280  assert(dhx.size()==dim_*dim_);
281  std::vector<vnl_rnpoly_solve_cmplx> df(dim_*dim_),dg(dim_),f(dim_),g(dim_);
282  std::vector<vnl_rnpoly_solve_cmplx> pows; // powers of variables [dim_ equations] [max_deg_ possible powers]
283 
284  ffunr(coeff,polyn,terms,x,pows,f,df);
285  gfunr(ideg,pdg,qdg,pows,g,dg);
286  assert(f.size()==dim_);
287  assert(g.size()==dim_);
288  assert(dg.size()==dim_);
289  assert(df.size()==dim_*dim_);
290 
291  double onemt=1.0 - t;
292  for (unsigned int j=0; j<dim_; ++j)
293  {
294  for (unsigned int i=0; i<dim_; ++i)
295  dhx[j*dim_+i] = df[j*dim_+i] * t;
296 
297  dhx[j*dim_+j] += dg[j]*onemt;
298  dht[j] = f[j] - g[j];
299  h[j] = f[j] * t + g[j] * onemt;
300  }
301 }
302 
303 
304 //------------------------ LU DECOMPOSITION --------------------------
305 //: This performs LU decomposition on a matrix.
306 static int ludcmp(std::vector<vnl_rnpoly_solve_cmplx>& a, std::vector<int>& indx)
307 {
308  std::vector<double> vv(dim_);
309 
310  // Loop over rows to get the implicit scaling information
311  for (unsigned int i=0; i<dim_; ++i)
312  {
313  double big = 0.0;
314  for (unsigned int j=0; j<dim_; ++j)
315  {
316  double temp = a[i*dim_+j].norm();
317  if (temp > big) big = temp;
318  }
319  if (big == 0.0) return 1;
320  vv[i]=1.0/std::sqrt(big);
321  }
322 
323  // This is the loop over columns of Crout's method
324  for (unsigned int j=0; j<dim_; ++j)
325  {
326  for (unsigned int i=0; i<j; ++i)
327  for (unsigned int k=0; k<i; ++k)
328  a[i*dim_+j] -= a[i*dim_+k] * a[k*dim_+j];
329 
330  // Initialize for the search for largest pivot element
331  double big = 0.0;
332  unsigned int imax = 0;
333 
334  for (unsigned int i=j; i<dim_; ++i)
335  {
336  for (unsigned int k=0; k<j; ++k)
337  a[i*dim_+j] -= a[i*dim_+k] * a[k*dim_+j];
338 
339  // Is the figure of merit for the pivot better than the best so far?
340  double rdum = vv[i]*a[i*dim_+j].norm();
341  if (rdum >= big) { big = rdum; imax = i; }
342  }
343 
344  // Do we need to interchange rows?
345  if (j != imax)
346  {
347  // Yes, do so...
348  for (unsigned int k=0; k<dim_; ++k)
349  {
350  vnl_rnpoly_solve_cmplx dum = a[imax*dim_+k];
351  a[imax*dim_+k] = a[j*dim_+k]; a[j*dim_+k] = dum;
352  }
353 
354  // Also interchange the scale factor
355  vv[imax]=vv[j];
356  }
357  indx[j]=imax;
358 
359  vnl_rnpoly_solve_cmplx& ajj = a[j*dim_+j];
360  if (ajj.norm() == 0.0)
361  ajj = epsilonZ;
362 
363  // Now, finally, divide by the pivot element
364  if (j+1 != dim_)
365  {
367 
368  // If the pivot element is zero the matrix is singular.
369  for (unsigned int i=j+1; i<dim_; ++i)
370  a[i*dim_+j] *= dum;
371  }
372  }
373  return 0;
374 }
375 
376 
377 // ------------------------- LU Back Substitution -------------------------
378 static void lubksb(std::vector<vnl_rnpoly_solve_cmplx> const& a,
379  std::vector<int> const& indx,
380  std::vector<vnl_rnpoly_solve_cmplx> const& bb,
381  std::vector<vnl_rnpoly_solve_cmplx>& b)
382 {
383  int ii=-1;
384  for (unsigned int k=0; k<dim_; ++k)
385  b[k] = bb[k];
386 
387  for (unsigned int i=0; i<dim_; ++i)
388  {
389  int ip = indx[i];
390  vnl_rnpoly_solve_cmplx sum = b[ip];
391  b[ip] = b[i];
392 
393  if (ii>=0)
394  for (unsigned int j=ii;j<i;++j)
395  sum -= a[i*dim_+j] * b[j];
396  else
397  // A nonzero element was encountered, so from now on we
398  // will have to do the sums in the loop above
399  if (sum.norm() > 0) ii = i;
400 
401  b[i] = sum;
402  }
403 
404  // Now do the backsubstitution
405  for (int i=dim_-1;i>=0;i--)
406  {
407  for (unsigned int j=i+1; j<dim_; ++j)
408  b[i] -= a[i*dim_+j] * b[j];
409 
410  b[i] /= a[i*dim_+i];
411  }
412 }
413 
414 
415 //-------------------------- LINNR -------------------
416 //: Solve a complex system of equations by using l-u decomposition and then back substitution.
417 static int linnr(std::vector<vnl_rnpoly_solve_cmplx>& dhx,
418  std::vector<vnl_rnpoly_solve_cmplx> const& rhs,
419  std::vector<vnl_rnpoly_solve_cmplx>& resid)
420 {
421  std::vector<int> irow(dim_);
422  if (ludcmp(dhx,irow)==1) return 1;
423  lubksb(dhx,irow,rhs,resid);
424  return 0;
425 }
426 
427 
428 //----------------------- XNORM --------------------
429 //: Finds the unit normal of a vector v
430 static double xnorm(std::vector<vnl_rnpoly_solve_cmplx> const& v)
431 {
432  assert(v.size()==dim_);
433  double txnorm=0.0;
434  for (unsigned int j=0; j<dim_; ++j)
435  txnorm += std::fabs(v[j].R) + std::fabs(v[j].C);
436  return txnorm;
437 }
438 
439 //---------------------- PREDICT ---------------------
440 //: Predict new x vector using Taylor's Expansion.
441 static void predict(std::vector<unsigned int> const& ideg,
442  std::vector<vnl_rnpoly_solve_cmplx> const& pdg,
443  std::vector<vnl_rnpoly_solve_cmplx> const& qdg,
444  double step, double& t,
445  std::vector<vnl_rnpoly_solve_cmplx>& x,
446  std::vector<int> const& polyn,
447  std::vector<double> const& coeff,
448  std::vector<unsigned int> const& terms)
449 {
450  assert(ideg.size()==dim_);
451  assert(terms.size()==dim_);
452  assert(x.size()==dim_);
453 
454  double maxdt =.2; // Maximum change in t for a given step. If dt is
455  // too large, there seems to be greater chance of
456  // jumping to another path. Set this to 1 if you
457  // don't care.
458  std::vector<vnl_rnpoly_solve_cmplx> dht(dim_),dhx(dim_*dim_),dz(dim_),h(dim_),rhs(dim_);
459  // Call the continuation function that we are tracing
460  hfunr(ideg,pdg,qdg,t,x,h,dhx,dht,polyn,coeff,terms);
461 
462  for (unsigned int j=0; j<dim_; ++j)
463  rhs[j] = - dht[j];
464 
465  // Call the function that solves a complex system of equations
466  if (linnr(dhx,rhs,dz) == 1) return;
467 
468  // Find the unit normal of a vector and normalize our step
469  double factor = step/(1+xnorm(dz));
470  if (factor>maxdt) factor = maxdt;
471 
472  bool tis1=true;
473  if (t+factor>1) { tis1 = false; factor = 1.0 - t; }
474 
475  // Update this path with the predicted next point
476  for (unsigned int j=0; j<dim_; ++j)
477  x[j] += dz[j] * factor;
478 
479  if (tis1) t += factor;
480  else t = 1.0;
481 }
482 
483 
484 //------------------------- CORRECT --------------------------
485 //: Correct the predicted point to lie near the actual curve
486 // Use Newton's Method to do this.
487 // Returns:
488 // 0: Converged
489 // 1: Singular Jacobian
490 // 2: Didn't converge in 'loop' iterations
491 // 3: If the magnitude of x > maxroot
492 static int correct(std::vector<unsigned int> const& ideg, int loop, double eps,
493  std::vector<vnl_rnpoly_solve_cmplx> const& pdg,
494  std::vector<vnl_rnpoly_solve_cmplx> const& qdg,
495  double t,
496  std::vector<vnl_rnpoly_solve_cmplx>& x,
497  std::vector<int> const& polyn,
498  std::vector<double> const& coeff,
499  std::vector<unsigned int> const& terms)
500 {
501  double maxroot= 1000;// Maximum size of root where it is considered heading to infinity
502  std::vector<vnl_rnpoly_solve_cmplx> dhx(dim_*dim_),dht(dim_),h(dim_),resid(dim_);
503 
504  assert(ideg.size()==dim_);
505  assert(terms.size()==dim_);
506  assert(x.size()==dim_);
507 
508  for (int i=0;i<loop;i++)
509  {
510  hfunr(ideg,pdg,qdg,t,x,h,dhx,dht,polyn,coeff,terms);
511 
512  // If linnr = 1, error
513  if (linnr(dhx,h,resid)==1) return 1;
514 
515  for (unsigned int j=0; j<dim_; ++j)
516  x[j] -= resid[j];
517 
518  double xresid = xnorm(resid);
519  if (xresid < eps) return 0;
520  if (xresid > maxroot) return 3;
521  }
522  return 2;
523 }
524 
525 
526 //-------------------------- TRACE ---------------------------
527 //: This is the continuation routine.
528 // It will trace a curve from a known point in the complex plane to an unknown
529 // point in the complex plane. The new end point is the root
530 // to a polynomial equation that we are trying to solve.
531 // It will return the following codes:
532 // 0: Maximum number of steps exceeded
533 // 1: Path converged
534 // 2: Step size became too small
535 // 3: Path Heading to infinity
536 // 4: Singular Jacobian on Path
537 static int trace(std::vector<vnl_rnpoly_solve_cmplx>& x,
538  std::vector<unsigned int> const& ideg,
539  std::vector<vnl_rnpoly_solve_cmplx> const& pdg,
540  std::vector<vnl_rnpoly_solve_cmplx> const& qdg,
541  std::vector<int> const& polyn,
542  std::vector<double> const& coeff,
543  std::vector<unsigned int> const& terms)
544 {
545  assert(ideg.size()==dim_);
546  assert(terms.size()==dim_);
547  assert(x.size()==dim_);
548 
549  int maxns=500; // Maximum number of path steps
550  int maxit=5; // Maximum number of iterations to correct a step.
551  // For each step, Newton-Raphson is used to correct
552  // the step. This should be at least 3 to improve
553  // the chances of convergence. If function is well
554  // behaved, fewer than maxit steps will be needed
555 
556  double eps=0; // epsilon value used in correct
557  double epsilonS=1.0e-3 * epsilonB;// smallest path step for t>.95
558  double stepmin=1.0e-5 * stepinit; // Minimum stepsize allowed
559  double step=stepinit; // stepsize
560  double t=0.0; // Continuation parameter 0<t<1
561  double oldt=0.0; // The previous t value
562  std::vector<vnl_rnpoly_solve_cmplx> oldx = x; // the previous path value
563  int nadv=0;
564 
565  for (int numstep=0;numstep<maxns;numstep++)
566  {
567  // Taylor approximate the next point
568  predict(ideg,pdg,qdg,step,t,x,polyn,coeff,terms);
569 
570  //if (t>1.0) t=1.0;
571 
572  if (t > .95)
573  {
574  if (eps != epsilonS) step = step/4.0;
575  eps = epsilonS;
576  }
577  else
578  eps = epsilonB;
579 #ifdef DEBUG
580  std::cout << "t=" << t << std::endl;
581 #endif
582 
583  if (t>=.99999) // Path converged
584  {
585 #ifdef DEBUG
586  std::cout << "path converged\n" << std::flush;
587 #endif
588  double factor = (1.0-oldt)/(t-oldt);
589  for (unsigned int j=0; j<dim_; ++j)
590  x[j] = oldx[j] + (x[j]-oldx[j]) * factor;
591  t = 1.0;
592  int cflag=correct(ideg,10*maxit,final_eps,pdg,qdg,t,x, polyn, coeff,terms);
593  if ((cflag==0) ||(cflag==2))
594  return 1; // Final Correction converged
595  else if (cflag==3)
596  return 3; // Heading to infinity
597  else return 4; // Singular solution
598  }
599 
600  // Newton's method brings us back to the curve
601  int cflag=correct(ideg,maxit,eps,pdg,qdg,t,x,polyn, coeff,terms);
602  if (cflag==0)
603  {
604  // Successful step
605  if ((++nadv)==maxit) { step *= 2; nadv=0; } // Increase the step size
606  // Make note of our new location
607  oldt = t;
608  oldx = x;
609  }
610  else
611  {
612  nadv=0;
613  step /= 2.0;
614 
615  if (cflag==3) return 3; // Path heading to infinity
616  if (step<stepmin) return 2; // Path failed StepSizeMin exceeded
617 
618  // Reset the values since we stepped to far, and try again
619  t = oldt;
620  x = oldx;
621  }
622  }// end of the loop numstep
623 
624  return 0;
625 }
626 
627 
628 //-------------------------- STRPTR ---------------------------
629 //: This will find a starting point on the 'g' function circle.
630 // The new point to start tracing is stored in the x array.
631 static void strptr(std::vector<unsigned int>& icount,
632  std::vector<unsigned int> const& ideg,
633  std::vector<vnl_rnpoly_solve_cmplx> const& r,
634  std::vector<vnl_rnpoly_solve_cmplx>& x)
635 {
636  assert(ideg.size()==dim_);
637  assert(r.size()==dim_);
638  x.resize(dim_);
639 
640  for (unsigned int i=0; i<dim_; ++i)
641  if (icount[i] >= ideg[i]) icount[i] = 1;
642  else { icount[i]++; break; }
643 
644  for (unsigned int j=0; j<dim_; ++j)
645  {
646  double angle = twopi / ideg[j] * icount[j];
647  x[j] = r[j] * vnl_rnpoly_solve_cmplx (std::cos(angle), std::sin(angle));
648  }
649 }
650 
651 
652 static std::vector<std::vector<vnl_rnpoly_solve_cmplx> >
653 Perform_Distributed_Task(std::vector<unsigned int> const& ideg,
654  std::vector<unsigned int> const& terms,
655  std::vector<int> const& polyn,
656  std::vector<double> const& coeff)
657 {
658  assert(ideg.size()==dim_);
659 
660  std::vector<std::vector<vnl_rnpoly_solve_cmplx> > sols;
661  std::vector<vnl_rnpoly_solve_cmplx> pdg, qdg, p, q, r, x;
662  std::vector<unsigned int> icount(dim_,1); icount[0]=0;
663  bool solflag; // flag used to remember if a root is found
664 #ifdef DEBUG
665  char const* FILENAM = "/tmp/cont.results";
666  std::ofstream F(FILENAM);
667  if (!F)
668  {
669  std::cerr<<"could not open "<<FILENAM<<" for writing\nplease erase old file first\n";
670  F = std::cerr;
671  }
672  else
673  std::cerr << "Writing to " << FILENAM << '\n';
674 #endif
675  // Initialize some variables
676  inptbr(p,q);
677  initr(ideg,p,q,r,pdg,qdg);
678 
679  // int Psize = 2*dim_*sizeof(double);
680  int totdegree = 1; // Total degree of the system
681  for (unsigned int j=0;j<dim_;j++) totdegree *= ideg[j];
682 
683  // ************* Send initial information ****************
684  //Initialize(dim_,maxns,maxdt,maxit,maxroot,
685  // terms,ideg,pdg,qdg,coeff,polyn);
686  while ((totdegree--) > 0)
687  {
688  // Compute path to trace
689  strptr(icount,ideg,r,x);
690 
691  // Tell the client which path you want it to trace
692  solflag = 1 == trace(x,ideg,pdg,qdg,polyn,coeff,terms);
693  // Save the solution for future reference
694  if (solflag)
695  {
696 #ifdef DEBUG
697  for (unsigned int i=0; i<dim_; ++i)
698  F << '<' << x[dim_-i-1].R << ' ' << x[dim_-i-1].C << '>';
699  F << std::endl;
700 #endif
701  sols.push_back(x);
702  }
703 #ifdef DEBUG
704  // print something out for each root
705  if (solflag) std::cout << '.';
706  else std::cout << '*';
707  std::cout.flush();
708 #endif
709  }
710 
711 #ifdef DEBUG
712  std::cout<< std::endl;
713 #endif
714 
715  return sols;
716 }
717 
718 
719 //----------------------- READ INPUT ----------------------
720 //: This will read the input polynomials from a data file.
721 void vnl_rnpoly_solve::Read_Input(std::vector<unsigned int>& ideg,
722  std::vector<unsigned int>& terms,
723  std::vector<int>& polyn,
724  std::vector<double>& coeff)
725 {
726  // Read the number of equations
727  dim_ = ps_.size();
728 
729  ideg.resize(dim_); terms.resize(dim_);
730  // Start reading in the array values
731  max_deg_=0;
732  max_nterms_=0;
733  for (unsigned int i=0;i<dim_;i++)
734  {
735  ideg[i] = ps_[i]->ideg_;
736  terms[i] = ps_[i]->nterms_;
737  if (ideg[i] > max_deg_)
738  max_deg_ = ideg[i];
739  if (terms[i] > max_nterms_)
740  max_nterms_ = terms[i];
741  }
742  coeff.resize(dim_*max_nterms_);
743  polyn.resize(dim_*max_nterms_*dim_);
744  for (unsigned int i=0;i<dim_;i++)
745  {
746  for (unsigned int k=0;k<terms[i];k++)
747  {
748  coeff[i*max_nterms_+k] = ps_[i]->coeffs_(k);
749  for (unsigned int j=0;j<dim_;j++)
750  {
751  int deg = ps_[i]->polyn_(k,j);
752  polyn[i*dim_*max_nterms_+k*dim_+j] = deg ? int(j*max_deg_)+deg-1 : -1;
753  }
754  }
755  }
756 }
757 
758 
760 {
761  while (r_.size() > 0) { delete r_.back(); r_.pop_back(); }
762  while (i_.size() > 0) { delete i_.back(); i_.pop_back(); }
763 }
764 
766 {
767  std::vector<unsigned int> ideg, terms;
768  std::vector<int> polyn;
769  std::vector<double> coeff;
770 
771  Read_Input(ideg,terms,polyn,coeff); // returns number of equations
772  assert(ideg.size()==dim_);
773  assert(terms.size()==dim_);
774  assert(polyn.size()==dim_*max_nterms_*dim_);
775  assert(coeff.size()==dim_*max_nterms_);
776 
777  int totdegree = 1;
778  for (unsigned int j=0; j<dim_; ++j) totdegree *= ideg[j];
779 
780  std::vector<std::vector<vnl_rnpoly_solve_cmplx> > ans = Perform_Distributed_Task(ideg,terms,polyn,coeff);
781 
782  // Print out the answers
783  vnl_vector<double> * rp, *ip;
784 #ifdef DEBUG
785  std::cout << "Total degree: " << totdegree << std::endl
786  << "# solutions : " << ans.size() << std::endl;
787 #endif
788  for (auto & an : ans)
789  {
790  assert(an.size()==dim_);
791  rp=new vnl_vector<double>(dim_); r_.push_back(rp);
792  ip=new vnl_vector<double>(dim_); i_.push_back(ip);
793  for (unsigned int j=0; j<dim_; ++j)
794  {
795 #ifdef DEBUG
796  std::cout << ans[i][j].R << " + j " << ans[i][j].C << std::endl;
797 #endif
798  (*rp)[j]=an[j].R; (*ip)[j]=an[j].C;
799  }
800 #ifdef DEBUG
801  std::cout<< std::endl;
802 #endif
803  }
804  return true;
805 }
bool compute()
Compute roots using continuation algorithm.
std::vector< vnl_real_npolynomial * > ps_
std::vector< vnl_vector< double > * > i_
vnl_rnpoly_solve_cmplx operator/(vnl_rnpoly_solve_cmplx const &Y) const
size_t size() const
Return the length, number of elements, dimension of this vector.
Definition: vnl_vector.h:126
vnl_rnpoly_solve_cmplx(double a=0, double b=0)
vnl_rnpoly_solve_cmplx & operator/=(vnl_rnpoly_solve_cmplx const &Y)
Namespace with standard math functions.
void Read_Input(std::vector< unsigned int > &ideg, std::vector< unsigned int > &terms, std::vector< int > &polyn, std::vector< double > &coeff)
This will read the input polynomials from a data file.
This is a local implementation of a minimal "complex number" class, for internal use only.
#define v
Definition: vnl_vector.h:42
vnl_rnpoly_solve_cmplx operator *(vnl_rnpoly_solve_cmplx const &Y) const
std::vector< vnl_vector< double > * > realroots(double tol=1e-12)
Return real roots only.
vnl_rnpoly_solve_cmplx operator+(vnl_rnpoly_solve_cmplx const &Y) const
vnl_rnpoly_solve_cmplx & operator-=(vnl_rnpoly_solve_cmplx const &Y)
vnl_rnpoly_solve_cmplx & operator *=(double T)
Solves for roots of system of real polynomials.
T angle(const vnl_vector_fixed< T, n > &a, const vnl_vector_fixed< T, n > &b)
std::vector< vnl_vector< double > * > r_
vnl_rnpoly_solve_cmplx operator-() const
vnl_rnpoly_solve_cmplx operator-(vnl_rnpoly_solve_cmplx const &Y) const
vnl_rnpoly_solve_cmplx & operator+=(vnl_rnpoly_solve_cmplx const &Y)