HMLP: High-performance Machine Learning Primitives
legendre_rule.hpp
1 #ifndef _LEGENDRE_RULE_HPP_
2 #define _LEGENDRE_RULE_HPP_
3 
4 #include <cstring>
5 
6 void cdgqf(int nt, int kind, double alpha, double beta, double t[], double wts[]);
7 void cgqf(int nt, int kind, double alpha, double beta, double a, double b, double t[], double wts[]);
8 double class_matrix(int kind, int m, double alpha, double beta, double aj[], double bj[]);
9 void imtqlx(int n, double d[], double e[], double z[]);
10 void parchk(int kind, int m, double alpha, double beta);
11 double r8_abs(double x);
12 double r8_epsilon();
13 double r8_sign(double x);
14 void r8mat_write(std::string output_filename, int m, int n, double table[]);
15 void rule_write(int order, std::string filename, double x[], double w[], double r[]);
16 void scqf(int nt, double t[], int mlt[], double wts[], int nwts, int ndx[], double swts[], double st[], int kind, double alpha, double beta, double a, double b);
17 void sgqf(int nt, double aj[], double bj[], double zemu, double t[], double wts[]);
18 void timestamp();
19 
20 # include <cstdlib>
21 # include <cmath>
22 # include <iostream>
23 # include <fstream>
24 # include <iomanip>
25 # include <ctime>
26 # include <cstring>
27 # include <cassert>
28 # include <pvfmm/legendre_rule.hpp>
29 
30 //using namespace std;
31 
32 //****************************************************************************80
33 /*
34 int main ( int argc, char *argv[] )
35 
36 // ***************************************************************************80
37 //
38 // Purpose:
39 //
40 // MAIN is the main program for LEGENDRE_RULE.
41 //
42 // Discussion:
43 //
44 // This program computes a standard Gauss-Legendre quadrature rule
45 // and writes it to a file.
46 //
47 // The user specifies:
48 // * the ORDER (number of points) in the rule
49 // * A, the left endpoint;
50 // * B, the right endpoint;
51 // * FILENAME, the root name of the output files.
52 //
53 // Licensing:
54 //
55 // This code is distributed under the GNU LGPL license.
56 //
57 // Modified:
58 //
59 // 23 February 2010
60 //
61 // Author:
62 //
63 // John Burkardt
64 //
65 {
66  double a;
67  double alpha;
68  double b;
69  double beta;
70  string filename;
71  int kind;
72  int order;
73  double *r;
74  double *w;
75  double *x;
76 
77  timestamp ( );
78  std::cout << "\n";
79  std::cout << "LEGENDRE_RULE\n";
80  std::cout << " C++ version\n";
81  std::cout << "\n";
82  std::cout << " Compiled on " << __DATE__ << " at " << __TIME__ << ".\n";
83  std::cout << "\n";
84  std::cout << " Compute a Gauss-Legendre rule for approximating\n";
85  std::cout << "\n";
86  std::cout << " Integral ( A <= x <= B ) f(x) dx\n";
87  std::cout << "\n";
88  std::cout << " of order ORDER.\n";
89  std::cout << "\n";
90  std::cout << " The user specifies ORDER, A, B and FILENAME.\n";
91  std::cout << "\n";
92  std::cout << " Order is the number of points.\n";
93  std::cout << "\n";
94  std::cout << " A is the left endpoint.\n";
95  std::cout << "\n";
96  std::cout << " B is the right endpoint.\n";
97  std::cout << "\n";
98  std::cout << " FILENAME is used to generate 3 files:\n";
99  std::cout << "\n";
100  std::cout << " filename_w.txt - the weight file\n";
101  std::cout << " filename_x.txt - the abscissa file.\n";
102  std::cout << " filename_r.txt - the region file.\n";
103 //
104 // Initialize parameters;
105 //
106  alpha = 0.0;
107  beta = 0.0;
108 //
109 // Get ORDER.
110 //
111  if ( 1 < argc )
112  {
113  order = atoi ( argv[1] );
114  }
115  else
116  {
117  std::cout << "\n";
118  std::cout << " Enter the value of ORDER (1 or greater)\n";
119  cin >> order;
120  }
121 //
122 // Get A.
123 //
124  if ( 2 < argc )
125  {
126  a = atof ( argv[2] );
127  }
128  else
129  {
130  std::cout << "\n";
131  std::cout << " Enter the value of A:\n";
132  cin >> a;
133  }
134 //
135 // Get B.
136 //
137  if ( 3 < argc )
138  {
139  b = atof ( argv[3] );
140  }
141  else
142  {
143  std::cout << "\n";
144  std::cout << " Enter the value of B:\n";
145  cin >> b;
146  }
147 //
148 // Get FILENAME:
149 //
150  if ( 4 < argc )
151  {
152  filename = argv[4];
153  }
154  else
155  {
156  std::cout << "\n";
157  std::cout << " Enter FILENAME, the \"root name\" of the quadrature files).\n";
158  cin >> filename;
159  }
160 //
161 // Input summary.
162 //
163  std::cout << "\n";
164  std::cout << " ORDER = " << order << "\n";
165  std::cout << " A = " << a << "\n";
166  std::cout << " B = " << b << "\n";
167  std::cout << " FILENAME = \"" << filename << "\".\n";
168 //
169 // Construct the rule.
170 //
171  w = new double[order];
172  x = new double[order];
173 
174  kind = 1;
175  cgqf ( order, kind, alpha, beta, a, b, x, w );
176 //
177 // Write the rule.
178 //
179  r = new double[2];
180  r[0] = a;
181  r[1] = b;
182 
183  rule_write ( order, filename, x, w, r );
184 //
185 // Terminate.
186 //
187  delete [] r;
188  delete [] w;
189  delete [] x;
190  std::cout << "\n";
191  std::cout << "LEGENDRE_RULE:\n";
192  std::cout << " Normal end of execution.\n";
193 
194  std::cout << "\n";
195  timestamp ( );
196 
197  return 0;
198 }*/
199 //****************************************************************************80
200 
201 inline void cdgqf ( int nt, int kind, double alpha, double beta, double t[],
202  double wts[] )
203 
204 //****************************************************************************80
205 //
206 // Purpose:
207 //
208 // CDGQF computes a Gauss quadrature formula with default A, B and simple knots.
209 //
210 // Discussion:
211 //
212 // This routine computes all the knots and weights of a Gauss quadrature
213 // formula with a classical weight function with default values for A and B,
214 // and only simple knots.
215 //
216 // There are no moments checks and no printing is done.
217 //
218 // Use routine EIQFS to evaluate a quadrature computed by CGQFS.
219 //
220 // Licensing:
221 //
222 // This code is distributed under the GNU LGPL license.
223 //
224 // Modified:
225 //
226 // 08 January 2010
227 //
228 // Author:
229 //
230 // Original FORTRAN77 version by Sylvan Elhay, Jaroslav Kautsky.
231 // C++ version by John Burkardt.
232 //
233 // Reference:
234 //
235 // Sylvan Elhay, Jaroslav Kautsky,
236 // Algorithm 655: IQPACK, FORTRAN Subroutines for the Weights of
237 // Interpolatory Quadrature,
238 // ACM Transactions on Mathematical Software,
239 // Volume 13, Number 4, December 1987, pages 399-415.
240 //
241 // Parameters:
242 //
243 // Input, int NT, the number of knots.
244 //
245 // Input, int KIND, the rule.
246 // 1, Legendre, (a,b) 1.0
247 // 2, Chebyshev Type 1, (a,b) ((b-x)*(x-a))^(-0.5)
248 // 3, Gegenbauer, (a,b) ((b-x)*(x-a))^alpha
249 // 4, Jacobi, (a,b) (b-x)^alpha*(x-a)^beta
250 // 5, Generalized Laguerre, (a,inf) (x-a)^alpha*exp(-b*(x-a))
251 // 6, Generalized Hermite, (-inf,inf) |x-a|^alpha*exp(-b*(x-a)^2)
252 // 7, Exponential, (a,b) |x-(a+b)/2.0|^alpha
253 // 8, Rational, (a,inf) (x-a)^alpha*(x+b)^beta
254 //
255 // Input, double ALPHA, the value of Alpha, if needed.
256 //
257 // Input, double BETA, the value of Beta, if needed.
258 //
259 // Output, double T[NT], the knots.
260 //
261 // Output, double WTS[NT], the weights.
262 //
263 {
264  double *aj;
265  double *bj;
266  double zemu;
267 
268  parchk ( kind, 2 * nt, alpha, beta );
269 //
270 // Get the Jacobi matrix and zero-th moment.
271 //
272  aj = new double[nt];
273  bj = new double[nt];
274 
275  zemu = class_matrix ( kind, nt, alpha, beta, aj, bj );
276 //
277 // Compute the knots and weights.
278 //
279  sgqf ( nt, aj, bj, zemu, t, wts );
280 
281  delete [] aj;
282  delete [] bj;
283 
284  return;
285 }
286 //****************************************************************************80
287 
288 inline void cgqf ( int nt, int kind, double alpha, double beta, double a, double b,
289  double t[], double wts[] )
290 
291 //****************************************************************************80
292 //
293 // Purpose:
294 //
295 // CGQF computes knots and weights of a Gauss quadrature formula.
296 //
297 // Discussion:
298 //
299 // The user may specify the interval (A,B).
300 //
301 // Only simple knots are produced.
302 //
303 // Use routine EIQFS to evaluate this quadrature formula.
304 //
305 // Licensing:
306 //
307 // This code is distributed under the GNU LGPL license.
308 //
309 // Modified:
310 //
311 // 16 February 2010
312 //
313 // Author:
314 //
315 // Original FORTRAN77 version by Sylvan Elhay, Jaroslav Kautsky.
316 // C++ version by John Burkardt.
317 //
318 // Reference:
319 //
320 // Sylvan Elhay, Jaroslav Kautsky,
321 // Algorithm 655: IQPACK, FORTRAN Subroutines for the Weights of
322 // Interpolatory Quadrature,
323 // ACM Transactions on Mathematical Software,
324 // Volume 13, Number 4, December 1987, pages 399-415.
325 //
326 // Parameters:
327 //
328 // Input, int NT, the number of knots.
329 //
330 // Input, int KIND, the rule.
331 // 1, Legendre, (a,b) 1.0
332 // 2, Chebyshev Type 1, (a,b) ((b-x)*(x-a))^-0.5)
333 // 3, Gegenbauer, (a,b) ((b-x)*(x-a))^alpha
334 // 4, Jacobi, (a,b) (b-x)^alpha*(x-a)^beta
335 // 5, Generalized Laguerre, (a,+oo) (x-a)^alpha*exp(-b*(x-a))
336 // 6, Generalized Hermite, (-oo,+oo) |x-a|^alpha*exp(-b*(x-a)^2)
337 // 7, Exponential, (a,b) |x-(a+b)/2.0|^alpha
338 // 8, Rational, (a,+oo) (x-a)^alpha*(x+b)^beta
339 // 9, Chebyshev Type 2, (a,b) ((b-x)*(x-a))^(+0.5)
340 //
341 // Input, double ALPHA, the value of Alpha, if needed.
342 //
343 // Input, double BETA, the value of Beta, if needed.
344 //
345 // Input, double A, B, the interval endpoints, or
346 // other parameters.
347 //
348 // Output, double T[NT], the knots.
349 //
350 // Output, double WTS[NT], the weights.
351 //
352 {
353  int i;
354  int *mlt;
355  int *ndx;
356 //
357 // Compute the Gauss quadrature formula for default values of A and B.
358 //
359  cdgqf ( nt, kind, alpha, beta, t, wts );
360 //
361 // Prepare to scale the quadrature formula to other weight function with
362 // valid A and B.
363 //
364  mlt = new int[nt];
365  for ( i = 0; i < nt; i++ )
366  {
367  mlt[i] = 1;
368  }
369  ndx = new int[nt];
370  for ( i = 0; i < nt; i++ )
371  {
372  ndx[i] = i + 1;
373  }
374  scqf ( nt, t, mlt, wts, nt, ndx, wts, t, kind, alpha, beta, a, b );
375 
376  delete [] mlt;
377  delete [] ndx;
378 
379  return;
380 }
381 //****************************************************************************80
382 
383 inline double class_matrix ( int kind, int m, double alpha, double beta, double aj[],
384  double bj[] )
385 
386 //****************************************************************************80
387 //
388 // Purpose:
389 //
390 // CLASS_MATRIX computes the Jacobi matrix for a quadrature rule.
391 //
392 // Discussion:
393 //
394 // This routine computes the diagonal AJ and sub-diagonal BJ
395 // elements of the order M tridiagonal symmetric Jacobi matrix
396 // associated with the polynomials orthogonal with respect to
397 // the weight function specified by KIND.
398 //
399 // For weight functions 1-7, M elements are defined in BJ even
400 // though only M-1 are needed. For weight function 8, BJ(M) is
401 // set to zero.
402 //
403 // The zero-th moment of the weight function is returned in ZEMU.
404 //
405 // Licensing:
406 //
407 // This code is distributed under the GNU LGPL license.
408 //
409 // Modified:
410 //
411 // 08 January 2010
412 //
413 // Author:
414 //
415 // Original FORTRAN77 version by Sylvan Elhay, Jaroslav Kautsky.
416 // C++ version by John Burkardt.
417 //
418 // Reference:
419 //
420 // Sylvan Elhay, Jaroslav Kautsky,
421 // Algorithm 655: IQPACK, FORTRAN Subroutines for the Weights of
422 // Interpolatory Quadrature,
423 // ACM Transactions on Mathematical Software,
424 // Volume 13, Number 4, December 1987, pages 399-415.
425 //
426 // Parameters:
427 //
428 // Input, int KIND, the rule.
429 // 1, Legendre, (a,b) 1.0
430 // 2, Chebyshev Type 1, (a,b) ((b-x)*(x-a))^(-0.5)
431 // 3, Gegenbauer, (a,b) ((b-x)*(x-a))^alpha
432 // 4, Jacobi, (a,b) (b-x)^alpha*(x-a)^beta
433 // 5, Generalized Laguerre, (a,inf) (x-a)^alpha*exp(-b*(x-a))
434 // 6, Generalized Hermite, (-inf,inf) |x-a|^alpha*exp(-b*(x-a)^2)
435 // 7, Exponential, (a,b) |x-(a+b)/2.0|^alpha
436 // 8, Rational, (a,inf) (x-a)^alpha*(x+b)^beta
437 //
438 // Input, int M, the order of the Jacobi matrix.
439 //
440 // Input, double ALPHA, the value of Alpha, if needed.
441 //
442 // Input, double BETA, the value of Beta, if needed.
443 //
444 // Output, double AJ[M], BJ[M], the diagonal and subdiagonal
445 // of the Jacobi matrix.
446 //
447 // Output, double CLASS_MATRIX, the zero-th moment.
448 //
449 {
450  double a2b2;
451  double ab;
452  double aba;
453  double abi;
454  double abj;
455  double abti;
456  double apone;
457  int i;
458  double pi = 3.14159265358979323846264338327950;
459  double zemu=0;
460 
461  parchk ( kind, 2 * m - 1, alpha, beta );
462 
463 /*
464  double temp = r8_epsilon ( );
465  double temp2 = 0.5;
466  if ( 500.0 * temp < r8_abs ( pow ( tgamma ( temp2 ), 2 ) - pi ) )
467  {
468  std::cout << "\n";
469  std::cout << "CLASS_MATRIX - Fatal error!\n";
470  std::cout << " Gamma function does not match machine parameters.\n";
471  exit ( 1 );
472  }
473 */
474  if ( kind == 1 )
475  {
476  ab = 0.0;
477 
478  zemu = 2.0 / ( ab + 1.0 );
479 
480  for ( i = 0; i < m; i++ )
481  {
482  aj[i] = 0.0;
483  }
484 
485  for ( i = 1; i <= m; i++ )
486  {
487  abi = i + ab * ( i % 2 );
488  abj = 2 * i + ab;
489  bj[i-1] = sqrt ( abi * abi / ( abj * abj - 1.0 ) );
490  }
491  }
492  else if ( kind == 2 )
493  {
494  zemu = pi;
495 
496  for ( i = 0; i < m; i++ )
497  {
498  aj[i] = 0.0;
499  }
500 
501  bj[0] = sqrt ( 0.5 );
502  for ( i = 1; i < m; i++ )
503  {
504  bj[i] = 0.5;
505  }
506  }
507  else if ( kind == 3 )
508  {
509  ab = alpha * 2.0;
510  zemu = pow ( 2.0, ab + 1.0 ) * pow ( tgamma ( alpha + 1.0 ), 2 )
511  / tgamma ( ab + 2.0 );
512 
513  for ( i = 0; i < m; i++ )
514  {
515  aj[i] = 0.0;
516  }
517 
518  bj[0] = sqrt ( 1.0 / ( 2.0 * alpha + 3.0 ) );
519  for ( i = 2; i <= m; i++ )
520  {
521  bj[i-1] = sqrt ( i * ( i + ab ) / ( 4.0 * pow ( i + alpha, 2 ) - 1.0 ) );
522  }
523  }
524  else if ( kind == 4 )
525  {
526  ab = alpha + beta;
527  abi = 2.0 + ab;
528  zemu = pow ( 2.0, ab + 1.0 ) * tgamma ( alpha + 1.0 )
529  * tgamma ( beta + 1.0 ) / tgamma ( abi );
530  aj[0] = ( beta - alpha ) / abi;
531  bj[0] = sqrt ( 4.0 * ( 1.0 + alpha ) * ( 1.0 + beta )
532  / ( ( abi + 1.0 ) * abi * abi ) );
533  a2b2 = beta * beta - alpha * alpha;
534 
535  for ( i = 2; i <= m; i++ )
536  {
537  abi = 2.0 * i + ab;
538  aj[i-1] = a2b2 / ( ( abi - 2.0 ) * abi );
539  abi = abi * abi;
540  bj[i-1] = sqrt ( 4.0 * i * ( i + alpha ) * ( i + beta ) * ( i + ab )
541  / ( ( abi - 1.0 ) * abi ) );
542  }
543  }
544  else if ( kind == 5 )
545  {
546  zemu = tgamma ( alpha + 1.0 );
547 
548  for ( i = 1; i <= m; i++ )
549  {
550  aj[i-1] = 2.0 * i - 1.0 + alpha;
551  bj[i-1] = sqrt ( i * ( i + alpha ) );
552  }
553  }
554  else if ( kind == 6 )
555  {
556  zemu = tgamma ( ( alpha + 1.0 ) / 2.0 );
557 
558  for ( i = 0; i < m; i++ )
559  {
560  aj[i] = 0.0;
561  }
562 
563  for ( i = 1; i <= m; i++ )
564  {
565  bj[i-1] = sqrt ( ( i + alpha * ( i % 2 ) ) / 2.0 );
566  }
567  }
568  else if ( kind == 7 )
569  {
570  ab = alpha;
571  zemu = 2.0 / ( ab + 1.0 );
572 
573  for ( i = 0; i < m; i++ )
574  {
575  aj[i] = 0.0;
576  }
577 
578  for ( i = 1; i <= m; i++ )
579  {
580  abi = i + ab * ( i % 2 );
581  abj = 2 * i + ab;
582  bj[i-1] = sqrt ( abi * abi / ( abj * abj - 1.0 ) );
583  }
584  }
585  else if ( kind == 8 )
586  {
587  ab = alpha + beta;
588  zemu = tgamma ( alpha + 1.0 ) * tgamma ( - ( ab + 1.0 ) )
589  / tgamma ( - beta );
590  apone = alpha + 1.0;
591  aba = ab * apone;
592  aj[0] = - apone / ( ab + 2.0 );
593  bj[0] = - aj[0] * ( beta + 1.0 ) / ( ab + 2.0 ) / ( ab + 3.0 );
594  for ( i = 2; i <= m; i++ )
595  {
596  abti = ab + 2.0 * i;
597  aj[i-1] = aba + 2.0 * ( ab + i ) * ( i - 1 );
598  aj[i-1] = - aj[i-1] / abti / ( abti - 2.0 );
599  }
600 
601  for ( i = 2; i <= m - 1; i++ )
602  {
603  abti = ab + 2.0 * i;
604  bj[i-1] = i * ( alpha + i ) / ( abti - 1.0 ) * ( beta + i )
605  / ( abti * abti ) * ( ab + i ) / ( abti + 1.0 );
606  }
607  bj[m-1] = 0.0;
608  for ( i = 0; i < m; i++ )
609  {
610  bj[i] = sqrt ( bj[i] );
611  }
612  }
613 
614  return zemu;
615 }
616 //****************************************************************************80
617 
618 inline void imtqlx ( int n, double d[], double e[], double z[] )
619 
620 //****************************************************************************80
621 //
622 // Purpose:
623 //
624 // IMTQLX diagonalizes a symmetric tridiagonal matrix.
625 //
626 // Discussion:
627 //
628 // This routine is a slightly modified version of the EISPACK routine to
629 // perform the implicit QL algorithm on a symmetric tridiagonal matrix.
630 //
631 // The authors thank the authors of EISPACK for permission to use this
632 // routine.
633 //
634 // It has been modified to produce the product Q' * Z, where Z is an input
635 // vector and Q is the orthogonal matrix diagonalizing the input matrix.
636 // The changes consist (essentialy) of applying the orthogonal transformations
637 // directly to Z as they are generated.
638 //
639 // Licensing:
640 //
641 // This code is distributed under the GNU LGPL license.
642 //
643 // Modified:
644 //
645 // 08 January 2010
646 //
647 // Author:
648 //
649 // Original FORTRAN77 version by Sylvan Elhay, Jaroslav Kautsky.
650 // C++ version by John Burkardt.
651 //
652 // Reference:
653 //
654 // Sylvan Elhay, Jaroslav Kautsky,
655 // Algorithm 655: IQPACK, FORTRAN Subroutines for the Weights of
656 // Interpolatory Quadrature,
657 // ACM Transactions on Mathematical Software,
658 // Volume 13, Number 4, December 1987, pages 399-415.
659 //
660 // Roger Martin, James Wilkinson,
661 // The Implicit QL Algorithm,
662 // Numerische Mathematik,
663 // Volume 12, Number 5, December 1968, pages 377-383.
664 //
665 // Parameters:
666 //
667 // Input, int N, the order of the matrix.
668 //
669 // Input/output, double D(N), the diagonal entries of the matrix.
670 // On output, the information in D has been overwritten.
671 //
672 // Input/output, double E(N), the subdiagonal entries of the
673 // matrix, in entries E(1) through E(N-1). On output, the information in
674 // E has been overwritten.
675 //
676 // Input/output, double Z(N). On input, a vector. On output,
677 // the value of Q' * Z, where Q is the matrix that diagonalizes the
678 // input symmetric tridiagonal matrix.
679 //
680 {
681  double b;
682  double c;
683  double f;
684  double g;
685  int i;
686  int ii;
687  int itn = 30;
688  int j;
689  int k;
690  int l;
691  int m=0;
692  int mml;
693  double p;
694  double prec;
695  double r;
696  double s;
697 
698  prec = r8_epsilon ( );
699 
700  if ( n == 1 )
701  {
702  return;
703  }
704 
705  e[n-1] = 0.0;
706 
707  for ( l = 1; l <= n; l++ )
708  {
709  j = 0;
710  for ( ; ; )
711  {
712  for ( m = l; m <= n; m++ )
713  {
714  if ( m == n )
715  {
716  break;
717  }
718 
719  if ( r8_abs ( e[m-1] ) <= prec * ( r8_abs ( d[m-1] ) + r8_abs ( d[m] ) ) )
720  {
721  break;
722  }
723  }
724  p = d[l-1];
725  if ( m == l )
726  {
727  break;
728  }
729  if ( itn <= j )
730  {
731  std::cout << "\n";
732  std::cout << "IMTQLX - Fatal error!\n";
733  std::cout << " Iteration limit exceeded\n";
734  exit ( 1 );
735  }
736  j = j + 1;
737  g = ( d[l] - p ) / ( 2.0 * e[l-1] );
738  r = sqrt ( g * g + 1.0 );
739  g = d[m-1] - p + e[l-1] / ( g + r8_abs ( r ) * r8_sign ( g ) );
740  s = 1.0;
741  c = 1.0;
742  p = 0.0;
743  mml = m - l;
744 
745  for ( ii = 1; ii <= mml; ii++ )
746  {
747  i = m - ii;
748  f = s * e[i-1];
749  b = c * e[i-1];
750 
751  if ( r8_abs ( g ) <= r8_abs ( f ) )
752  {
753  c = g / f;
754  r = sqrt ( c * c + 1.0 );
755  e[i] = f * r;
756  s = 1.0 / r;
757  c = c * s;
758  }
759  else
760  {
761  s = f / g;
762  r = sqrt ( s * s + 1.0 );
763  e[i] = g * r;
764  c = 1.0 / r;
765  s = s * c;
766  }
767  g = d[i] - p;
768  r = ( d[i-1] - g ) * s + 2.0 * c * b;
769  p = s * r;
770  d[i] = g + p;
771  g = c * r - b;
772  f = z[i];
773  z[i] = s * z[i-1] + c * f;
774  z[i-1] = c * z[i-1] - s * f;
775  }
776  d[l-1] = d[l-1] - p;
777  e[l-1] = g;
778  e[m-1] = 0.0;
779  }
780  }
781 //
782 // Sorting.
783 //
784  for ( ii = 2; ii <= m; ii++ )
785  {
786  i = ii - 1;
787  k = i;
788  p = d[i-1];
789 
790  for ( j = ii; j <= n; j++ )
791  {
792  if ( d[j-1] < p )
793  {
794  k = j;
795  p = d[j-1];
796  }
797  }
798 
799  if ( k != i )
800  {
801  d[k-1] = d[i-1];
802  d[i-1] = p;
803  p = z[i-1];
804  z[i-1] = z[k-1];
805  z[k-1] = p;
806  }
807  }
808  return;
809 }
810 //****************************************************************************80
811 
812 inline void parchk ( int kind, int m, double alpha, double beta )
813 
814 //****************************************************************************80
815 //
816 // Purpose:
817 //
818 // PARCHK checks parameters ALPHA and BETA for classical weight functions.
819 //
820 // Licensing:
821 //
822 // This code is distributed under the GNU LGPL license.
823 //
824 // Modified:
825 //
826 // 07 January 2010
827 //
828 // Author:
829 //
830 // Original FORTRAN77 version by Sylvan Elhay, Jaroslav Kautsky.
831 // C++ version by John Burkardt.
832 //
833 // Reference:
834 //
835 // Sylvan Elhay, Jaroslav Kautsky,
836 // Algorithm 655: IQPACK, FORTRAN Subroutines for the Weights of
837 // Interpolatory Quadrature,
838 // ACM Transactions on Mathematical Software,
839 // Volume 13, Number 4, December 1987, pages 399-415.
840 //
841 // Parameters:
842 //
843 // Input, int KIND, the rule.
844 // 1, Legendre, (a,b) 1.0
845 // 2, Chebyshev Type 1, (a,b) ((b-x)*(x-a))^(-0.5)
846 // 3, Gegenbauer, (a,b) ((b-x)*(x-a))^alpha
847 // 4, Jacobi, (a,b) (b-x)^alpha*(x-a)^beta
848 // 5, Generalized Laguerre, (a,inf) (x-a)^alpha*exp(-b*(x-a))
849 // 6, Generalized Hermite, (-inf,inf) |x-a|^alpha*exp(-b*(x-a)^2)
850 // 7, Exponential, (a,b) |x-(a+b)/2.0|^alpha
851 // 8, Rational, (a,inf) (x-a)^alpha*(x+b)^beta
852 //
853 // Input, int M, the order of the highest moment to
854 // be calculated. This value is only needed when KIND = 8.
855 //
856 // Input, double ALPHA, BETA, the parameters, if required
857 // by the value of KIND.
858 //
859 {
860  double tmp;
861 
862  if ( kind <= 0 )
863  {
864  std::cout << "\n";
865  std::cout << "PARCHK - Fatal error!\n";
866  std::cout << " KIND <= 0.\n";
867  exit ( 1 );
868  }
869 //
870 // Check ALPHA for Gegenbauer, Jacobi, Laguerre, Hermite, Exponential.
871 //
872  if ( 3 <= kind && alpha <= -1.0 )
873  {
874  std::cout << "\n";
875  std::cout << "PARCHK - Fatal error!\n";
876  std::cout << " 3 <= KIND and ALPHA <= -1.\n";
877  exit ( 1 );
878  }
879 //
880 // Check BETA for Jacobi.
881 //
882  if ( kind == 4 && beta <= -1.0 )
883  {
884  std::cout << "\n";
885  std::cout << "PARCHK - Fatal error!\n";
886  std::cout << " KIND == 4 and BETA <= -1.0.\n";
887  exit ( 1 );
888  }
889 //
890 // Check ALPHA and BETA for rational.
891 //
892  if ( kind == 8 )
893  {
894  tmp = alpha + beta + m + 1.0;
895  if ( 0.0 <= tmp || tmp <= beta )
896  {
897  std::cout << "\n";
898  std::cout << "PARCHK - Fatal error!\n";
899  std::cout << " KIND == 8 but condition on ALPHA and BETA fails.\n";
900  exit ( 1 );
901  }
902  }
903  return;
904 }
905 //****************************************************************************80
906 
907 inline double r8_abs ( double x )
908 
909 //****************************************************************************80
910 //
911 // Purpose:
912 //
913 // R8_ABS returns the absolute value of an R8.
914 //
915 // Licensing:
916 //
917 // This code is distributed under the GNU LGPL license.
918 //
919 // Modified:
920 //
921 // 14 November 2006
922 //
923 // Author:
924 //
925 // John Burkardt
926 //
927 // Parameters:
928 //
929 // Input, double X, the quantity whose absolute value is desired.
930 //
931 // Output, double R8_ABS, the absolute value of X.
932 //
933 {
934  double value;
935 
936  if ( 0.0 <= x )
937  {
938  value = x;
939  }
940  else
941  {
942  value = - x;
943  }
944  return value;
945 }
946 //****************************************************************************80
947 
948 inline double r8_epsilon ( )
949 
950 //****************************************************************************80
951 //
952 // Purpose:
953 //
954 // R8_EPSILON returns the R8 roundoff unit.
955 //
956 // Discussion:
957 //
958 // The roundoff unit is a number R which is a power of 2 with the
959 // property that, to the precision of the computer's arithmetic,
960 // 1 < 1 + R
961 // but
962 // 1 = ( 1 + R / 2 )
963 //
964 // Licensing:
965 //
966 // This code is distributed under the GNU LGPL license.
967 //
968 // Modified:
969 //
970 // 01 July 2004
971 //
972 // Author:
973 //
974 // John Burkardt
975 //
976 // Parameters:
977 //
978 // Output, double R8_EPSILON, the R8 round-off unit.
979 //
980 {
981  double value;
982 
983  value = 1.0;
984 
985  while ( 1.0 < ( double ) ( 1.0 + value ) )
986  {
987  value = value / 2.0;
988  }
989 
990  value = 2.0 * value;
991 
992  return value;
993 }
994 //****************************************************************************80
995 
996 inline double r8_sign ( double x )
997 
998 //****************************************************************************80
999 //
1000 // Purpose:
1001 //
1002 // R8_SIGN returns the sign of an R8.
1003 //
1004 // Licensing:
1005 //
1006 // This code is distributed under the GNU LGPL license.
1007 //
1008 // Modified:
1009 //
1010 // 18 October 2004
1011 //
1012 // Author:
1013 //
1014 // John Burkardt
1015 //
1016 // Parameters:
1017 //
1018 // Input, double X, the number whose sign is desired.
1019 //
1020 // Output, double R8_SIGN, the sign of X.
1021 //
1022 {
1023  double value;
1024 
1025  if ( x < 0.0 )
1026  {
1027  value = -1.0;
1028  }
1029  else
1030  {
1031  value = 1.0;
1032  }
1033  return value;
1034 }
1035 //****************************************************************************80
1036 
1037 inline void r8mat_write ( std::string output_filename, int m, int n, double table[] )
1038 
1039 //****************************************************************************80
1040 //
1041 // Purpose:
1042 //
1043 // R8MAT_WRITE writes an R8MAT file with no header.
1044 //
1045 // Licensing:
1046 //
1047 // This code is distributed under the GNU LGPL license.
1048 //
1049 // Modified:
1050 //
1051 // 29 June 2009
1052 //
1053 // Author:
1054 //
1055 // John Burkardt
1056 //
1057 // Parameters:
1058 //
1059 // Input, string OUTPUT_FILENAME, the output filename.
1060 //
1061 // Input, int M, the spatial dimension.
1062 //
1063 // Input, int N, the number of points.
1064 //
1065 // Input, double TABLE[M*N], the table data.
1066 //
1067 {
1068  int i;
1069  int j;
1070  std::ofstream output;
1071 //
1072 // Open the file.
1073 //
1074  output.open ( output_filename.c_str ( ) );
1075 
1076  if ( !output )
1077  {
1078  std::cerr << "\n";
1079  std::cerr << "R8MAT_WRITE - Fatal error!\n";
1080  std::cerr << " Could not open the output file.\n";
1081  return;
1082  }
1083 //
1084 // Write the data.
1085 //
1086  for ( j = 0; j < n; j++ )
1087  {
1088  for ( i = 0; i < m; i++ )
1089  {
1090  output << " " << std::setw(24) << std::setprecision(16) << table[i+j*m];
1091  }
1092  output << "\n";
1093  }
1094 //
1095 // Close the file.
1096 //
1097  output.close ( );
1098 
1099  return;
1100 }
1101 //****************************************************************************80
1102 
1103 inline void rule_write ( int order, std::string filename, double x[], double w[],
1104  double r[] )
1105 
1106 //****************************************************************************80
1107 //
1108 // Purpose:
1109 //
1110 // RULE_WRITE writes a quadrature rule to three files.
1111 //
1112 // Licensing:
1113 //
1114 // This code is distributed under the GNU LGPL license.
1115 //
1116 // Modified:
1117 //
1118 // 18 February 2010
1119 //
1120 // Author:
1121 //
1122 // John Burkardt
1123 //
1124 // Parameters:
1125 //
1126 // Input, int ORDER, the order of the rule.
1127 //
1128 // Input, double A, the left endpoint.
1129 //
1130 // Input, double B, the right endpoint.
1131 //
1132 // Input, string FILENAME, specifies the output filenames.
1133 // "filename_w.txt", "filename_x.txt", "filename_r.txt"
1134 // defining weights, abscissas, and region.
1135 //
1136 {
1137  std::string filename_r;
1138  std::string filename_w;
1139  std::string filename_x;
1140 
1141  filename_w = filename + "_w.txt";
1142  filename_x = filename + "_x.txt";
1143  filename_r = filename + "_r.txt";
1144 
1145  std::cout << "\n";
1146  std::cout << " Creating quadrature files.\n";
1147  std::cout << "\n";
1148  std::cout << " Root file name is \"" << filename << "\".\n";
1149  std::cout << "\n";
1150  std::cout << " Weight file will be \"" << filename_w << "\".\n";
1151  std::cout << " Abscissa file will be \"" << filename_x << "\".\n";
1152  std::cout << " Region file will be \"" << filename_r << "\".\n";
1153 
1154  r8mat_write ( filename_w, 1, order, w );
1155  r8mat_write ( filename_x, 1, order, x );
1156  r8mat_write ( filename_r, 1, 2, r );
1157 
1158  return;
1159 }
1160 //****************************************************************************80
1161 
1162 inline void scqf ( int nt, double t[], int mlt[], double wts[], int nwts, int ndx[],
1163  double swts[], double st[], int kind, double alpha, double beta, double a,
1164  double b )
1165 
1166 //****************************************************************************80
1167 //
1168 // Purpose:
1169 //
1170 // SCQF scales a quadrature formula to a nonstandard interval.
1171 //
1172 // Discussion:
1173 //
1174 // The arrays WTS and SWTS may coincide.
1175 //
1176 // The arrays T and ST may coincide.
1177 //
1178 // Licensing:
1179 //
1180 // This code is distributed under the GNU LGPL license.
1181 //
1182 // Modified:
1183 //
1184 // 16 February 2010
1185 //
1186 // Author:
1187 //
1188 // Original FORTRAN77 version by Sylvan Elhay, Jaroslav Kautsky.
1189 // C++ version by John Burkardt.
1190 //
1191 // Reference:
1192 //
1193 // Sylvan Elhay, Jaroslav Kautsky,
1194 // Algorithm 655: IQPACK, FORTRAN Subroutines for the Weights of
1195 // Interpolatory Quadrature,
1196 // ACM Transactions on Mathematical Software,
1197 // Volume 13, Number 4, December 1987, pages 399-415.
1198 //
1199 // Parameters:
1200 //
1201 // Input, int NT, the number of knots.
1202 //
1203 // Input, double T[NT], the original knots.
1204 //
1205 // Input, int MLT[NT], the multiplicity of the knots.
1206 //
1207 // Input, double WTS[NWTS], the weights.
1208 //
1209 // Input, int NWTS, the number of weights.
1210 //
1211 // Input, int NDX[NT], used to index the array WTS.
1212 // For more details see the comments in CAWIQ.
1213 //
1214 // Output, double SWTS[NWTS], the scaled weights.
1215 //
1216 // Output, double ST[NT], the scaled knots.
1217 //
1218 // Input, int KIND, the rule.
1219 // 1, Legendre, (a,b) 1.0
1220 // 2, Chebyshev Type 1, (a,b) ((b-x)*(x-a))^(-0.5)
1221 // 3, Gegenbauer, (a,b) ((b-x)*(x-a))^alpha
1222 // 4, Jacobi, (a,b) (b-x)^alpha*(x-a)^beta
1223 // 5, Generalized Laguerre, (a,+oo) (x-a)^alpha*exp(-b*(x-a))
1224 // 6, Generalized Hermite, (-oo,+oo) |x-a|^alpha*exp(-b*(x-a)^2)
1225 // 7, Exponential, (a,b) |x-(a+b)/2.0|^alpha
1226 // 8, Rational, (a,+oo) (x-a)^alpha*(x+b)^beta
1227 // 9, Chebyshev Type 2, (a,b) ((b-x)*(x-a))^(+0.5)
1228 //
1229 // Input, double ALPHA, the value of Alpha, if needed.
1230 //
1231 // Input, double BETA, the value of Beta, if needed.
1232 //
1233 // Input, double A, B, the interval endpoints.
1234 //
1235 {
1236  (void)(nwts); //UNUSED(nwts);
1237  double al=0;
1238  double be=0;
1239  int i;
1240  int k;
1241  int l;
1242  double p;
1243  double shft=0;
1244  double slp=0;
1245  double temp;
1246  double tmp;
1247 
1248  temp = r8_epsilon ( );
1249 
1250  parchk ( kind, 1, alpha, beta );
1251 
1252  if ( kind == 1 )
1253  {
1254  al = 0.0;
1255  be = 0.0;
1256  if ( r8_abs ( b - a ) <= temp )
1257  {
1258  std::cout << "\n";
1259  std::cout << "SCQF - Fatal error!\n";
1260  std::cout << " |B - A| too small.\n";
1261  exit ( 1 );
1262  }
1263  shft = ( a + b ) / 2.0;
1264  slp = ( b - a ) / 2.0;
1265  }
1266  else if ( kind == 2 )
1267  {
1268  al = -0.5;
1269  be = -0.5;
1270  if ( r8_abs ( b - a ) <= temp )
1271  {
1272  std::cout << "\n";
1273  std::cout << "SCQF - Fatal error!\n";
1274  std::cout << " |B - A| too small.\n";
1275  exit ( 1 );
1276  }
1277  shft = ( a + b ) / 2.0;
1278  slp = ( b - a ) / 2.0;
1279  }
1280  else if ( kind == 3 )
1281  {
1282  al = alpha;
1283  be = alpha;
1284  if ( r8_abs ( b - a ) <= temp )
1285  {
1286  std::cout << "\n";
1287  std::cout << "SCQF - Fatal error!\n";
1288  std::cout << " |B - A| too small.\n";
1289  exit ( 1 );
1290  }
1291  shft = ( a + b ) / 2.0;
1292  slp = ( b - a ) / 2.0;
1293  }
1294  else if ( kind == 4 )
1295  {
1296  al = alpha;
1297  be = beta;
1298 
1299  if ( r8_abs ( b - a ) <= temp )
1300  {
1301  std::cout << "\n";
1302  std::cout << "SCQF - Fatal error!\n";
1303  std::cout << " |B - A| too small.\n";
1304  exit ( 1 );
1305  }
1306  shft = ( a + b ) / 2.0;
1307  slp = ( b - a ) / 2.0;
1308  }
1309  else if ( kind == 5 )
1310  {
1311  if ( b <= 0.0 )
1312  {
1313  std::cout << "\n";
1314  std::cout << "SCQF - Fatal error!\n";
1315  std::cout << " B <= 0\n";
1316  exit ( 1 );
1317  }
1318  shft = a;
1319  slp = 1.0 / b;
1320  al = alpha;
1321  be = 0.0;
1322  }
1323  else if ( kind == 6 )
1324  {
1325  if ( b <= 0.0 )
1326  {
1327  std::cout << "\n";
1328  std::cout << "SCQF - Fatal error!\n";
1329  std::cout << " B <= 0.\n";
1330  exit ( 1 );
1331  }
1332  shft = a;
1333  slp = 1.0 / sqrt ( b );
1334  al = alpha;
1335  be = 0.0;
1336  }
1337  else if ( kind == 7 )
1338  {
1339  al = alpha;
1340  be = 0.0;
1341  if ( r8_abs ( b - a ) <= temp )
1342  {
1343  std::cout << "\n";
1344  std::cout << "SCQF - Fatal error!\n";
1345  std::cout << " |B - A| too small.\n";
1346  exit ( 1 );
1347  }
1348  shft = ( a + b ) / 2.0;
1349  slp = ( b - a ) / 2.0;
1350  }
1351  else if ( kind == 8 )
1352  {
1353  if ( a + b <= 0.0 )
1354  {
1355  std::cout << "\n";
1356  std::cout << "SCQF - Fatal error!\n";
1357  std::cout << " A + B <= 0.\n";
1358  exit ( 1 );
1359  }
1360  shft = a;
1361  slp = a + b;
1362  al = alpha;
1363  be = beta;
1364  }
1365  else if ( kind == 9 )
1366  {
1367  al = 0.5;
1368  be = 0.5;
1369  if ( r8_abs ( b - a ) <= temp )
1370  {
1371  std::cout << "\n";
1372  std::cout << "SCQF - Fatal error!\n";
1373  std::cout << " |B - A| too small.\n";
1374  exit ( 1 );
1375  }
1376  shft = ( a + b ) / 2.0;
1377  slp = ( b - a ) / 2.0;
1378  }
1379 
1380  p = pow ( slp, al + be + 1.0 );
1381 
1382  for ( k = 0; k < nt; k++ )
1383  {
1384  st[k] = shft + slp * t[k];
1385  l = abs ( ndx[k] );
1386 
1387  if ( l != 0 )
1388  {
1389  tmp = p;
1390  for ( i = l - 1; i <= l - 1 + mlt[k] - 1; i++ )
1391  {
1392  swts[i] = wts[i] * tmp;
1393  tmp = tmp * slp;
1394  }
1395  }
1396  }
1397  return;
1398 }
1399 //****************************************************************************80
1400 
1401 inline void sgqf ( int nt, double aj[], double bj[], double zemu, double t[],
1402  double wts[] )
1403 
1404 //****************************************************************************80
1405 //
1406 // Purpose:
1407 //
1408 // SGQF computes knots and weights of a Gauss Quadrature formula.
1409 //
1410 // Discussion:
1411 //
1412 // This routine computes all the knots and weights of a Gauss quadrature
1413 // formula with simple knots from the Jacobi matrix and the zero-th
1414 // moment of the weight function, using the Golub-Welsch technique.
1415 //
1416 // Licensing:
1417 //
1418 // This code is distributed under the GNU LGPL license.
1419 //
1420 // Modified:
1421 //
1422 // 08 January 2010
1423 //
1424 // Author:
1425 //
1426 // Original FORTRAN77 version by Sylvan Elhay, Jaroslav Kautsky.
1427 // C++ version by John Burkardt.
1428 //
1429 // Reference:
1430 //
1431 // Sylvan Elhay, Jaroslav Kautsky,
1432 // Algorithm 655: IQPACK, FORTRAN Subroutines for the Weights of
1433 // Interpolatory Quadrature,
1434 // ACM Transactions on Mathematical Software,
1435 // Volume 13, Number 4, December 1987, pages 399-415.
1436 //
1437 // Parameters:
1438 //
1439 // Input, int NT, the number of knots.
1440 //
1441 // Input, double AJ[NT], the diagonal of the Jacobi matrix.
1442 //
1443 // Input/output, double BJ[NT], the subdiagonal of the Jacobi
1444 // matrix, in entries 1 through NT-1. On output, BJ has been overwritten.
1445 //
1446 // Input, double ZEMU, the zero-th moment of the weight function.
1447 //
1448 // Output, double T[NT], the knots.
1449 //
1450 // Output, double WTS[NT], the weights.
1451 //
1452 {
1453  int i;
1454 //
1455 // Exit if the zero-th moment is not positive.
1456 //
1457  if ( zemu <= 0.0 )
1458  {
1459  std::cout << "\n";
1460  std::cout << "SGQF - Fatal error!\n";
1461  std::cout << " ZEMU <= 0.\n";
1462  exit ( 1 );
1463  }
1464 //
1465 // Set up vectors for IMTQLX.
1466 //
1467  for ( i = 0; i < nt; i++ )
1468  {
1469  t[i] = aj[i];
1470  }
1471  wts[0] = sqrt ( zemu );
1472  for ( i = 1; i < nt; i++ )
1473  {
1474  wts[i] = 0.0;
1475  }
1476 //
1477 // Diagonalize the Jacobi matrix.
1478 //
1479  imtqlx ( nt, t, bj, wts );
1480 
1481  for ( i = 0; i < nt; i++ )
1482  {
1483  wts[i] = wts[i] * wts[i];
1484  }
1485 
1486  return;
1487 }
1488 //****************************************************************************80
1489 
1490 inline void timestamp ( )
1491 
1492 //****************************************************************************80
1493 //
1494 // Purpose:
1495 //
1496 // TIMESTAMP prints the current YMDHMS date as a time stamp.
1497 //
1498 // Example:
1499 //
1500 // 31 May 2001 09:45:54 AM
1501 //
1502 // Licensing:
1503 //
1504 // This code is distributed under the GNU LGPL license.
1505 //
1506 // Modified:
1507 //
1508 // 08 July 2009
1509 //
1510 // Author:
1511 //
1512 // John Burkardt
1513 //
1514 // Parameters:
1515 //
1516 // None
1517 //
1518 {
1519 # define TIME_SIZE 40
1520 
1521  static char time_buffer[TIME_SIZE];
1522  const struct std::tm *tm_ptr;
1523  size_t len;
1524  std::time_t now;
1525 
1526  now = std::time ( NULL );
1527  tm_ptr = std::localtime ( &now );
1528 
1529  len = std::strftime ( time_buffer, TIME_SIZE, "%d %B %Y %I:%M:%S %p", tm_ptr );
1530  assert(len>0);
1531  std::cout << time_buffer << "\n";
1532 
1533  return;
1534 # undef TIME_SIZE
1535 }
1536 
1537 #endif