# include # include # include # include # include # include using namespace std; # include "condition.hpp" # include "r8lib.hpp" //****************************************************************************80 double *combin ( double alpha, double beta, int n ) //****************************************************************************80 // // Purpose: // // COMBIN returns the COMBIN matrix. // // Discussion: // // This matrix is known as the combinatorial matrix. // // Formula: // // If ( I = J ) then // A(I,J) = ALPHA + BETA // else // A(I,J) = BETA // // Example: // // N = 5, ALPHA = 2, BETA = 3 // // 5 3 3 3 3 // 3 5 3 3 3 // 3 3 5 3 3 // 3 3 3 5 3 // 3 3 3 3 5 // // Properties: // // A is symmetric: A' = A. // // Because A is symmetric, it is normal. // // Because A is normal, it is diagonalizable. // // A is persymmetric: A(I,J) = A(N+1-J,N+1-I). // // A is a circulant matrix: each row is shifted once to get the next row. // // det ( A ) = ALPHA^(N-1) * ( ALPHA + N * BETA ). // // A has constant row sums. // // Because A has constant row sums, // it has an eigenvalue with this value, // and a (right) eigenvector of ( 1, 1, 1, ..., 1 ). // // A has constant column sums. // // Because A has constant column sums, // it has an eigenvalue with this value, // and a (left) eigenvector of ( 1, 1, 1, ..., 1 ). // // LAMBDA(1:N-1) = ALPHA, // LAMBDA(N) = ALPHA + N * BETA. // // The eigenvector associated with LAMBDA(N) is (1,1,1,...,1)/sqrt(N). // // The other N-1 eigenvectors are simply any (orthonormal) basis // for the space perpendicular to (1,1,1,...,1). // // A is nonsingular if ALPHA /= 0 and ALPHA + N * BETA /= 0. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 08 June 2008 // // Author: // // John Burkardt // // Reference: // // Robert Gregory, David Karney, // A Collection of Matrices for Testing Computational Algorithms, // Wiley, 1969, // ISBN: 0882756494, // LC: QA263.68 // // Donald Knuth, // The Art of Computer Programming, // Volume 1, Fundamental Algorithms, Second Edition, // Addison-Wesley, Reading, Massachusetts, 1973, page 36. // // Parameters: // // Input, double ALPHA, BETA, scalars that define A. // // Input, int N, the order of the matrix. // // Output, double COMBIN[N*N], the matrix. // { double *a; int i; int j; a = new double[n*n]; for ( j = 0; j < n; j++ ) { for ( i = 0; i < n; i++ ) { if ( i == j ) { a[i+j*n] = alpha + beta; } else { a[i+j*n] = beta; } } } return a; } //****************************************************************************80 double *combin_inverse ( double alpha, double beta, int n ) //****************************************************************************80 // // Purpose: // // COMBIN_INVERSE returns the inverse of the COMBIN matrix. // // Formula: // // if ( I = J ) // A(I,J) = (ALPHA+(N-1)*BETA) / (ALPHA*(ALPHA+N*BETA)) // else // A(I,J) = - BETA / (ALPHA*(ALPHA+N*BETA)) // // Example: // // N = 5, ALPHA = 2, BETA = 3 // // 14 -3 -3 -3 -3 // -3 14 -3 -3 -3 // 1/34 * -3 -3 14 -3 -3 // -3 -3 -3 14 -3 // -3 -3 -3 -3 14 // // Properties: // // A is symmetric: A' = A. // // Because A is symmetric, it is normal. // // Because A is normal, it is diagonalizable. // // A is persymmetric: A(I,J) = A(N+1-J,N+1-I). // // A is a circulant matrix: each row is shifted once to get the next row. // // A is Toeplitz: constant along diagonals. // // det ( A ) = 1 / (ALPHA^(N-1) * (ALPHA+N*BETA)). // // A is well defined if ALPHA /= 0 and ALPHA+N*BETA /= 0. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 08 June 2008 // // Author: // // John Burkardt // // Reference: // // Donald Knuth, // The Art of Computer Programming, // Volume 1, Fundamental Algorithms, Second Edition, // Addison-Wesley, Reading, Massachusetts, 1973, page 36. // // Parameters: // // Input, double ALPHA, BETA, scalars that define the matrix. // // Input, int N, the order of the matrix. // // Output, double COMBIN_INVERSE[N*N], the matrix. // { double *a; double bot; int i; int j; if ( alpha == 0.0 ) { cerr << "\n"; cerr << "COMBIN_INVERSE - Fatal error!\n"; cerr << " The entries of the matrix are undefined\n"; cerr << " because ALPHA = 0.\n"; exit ( 1 ); } else if ( alpha + n * beta == 0.0 ) { cerr << "\n"; cerr << "COMBIN_INVERSE - Fatal error!\n"; cerr << " The entries of the matrix are undefined\n"; cerr << " because ALPHA+N*BETA is zero.\n"; exit ( 1 ); } a = new double[n*n]; bot = alpha * ( alpha + ( double ) ( n ) * beta ); for ( j = 0; j < n; j++ ) { for ( i = 0; i < n; i++ ) { if ( i == j ) { a[i+j*n] = ( alpha + ( double ) ( n - 1 ) * beta ) / bot; } else { a[i+j*n] = - beta / bot; } } } return a; } //****************************************************************************80 double condition_hager ( int n, double a[] ) //****************************************************************************80 // // Purpose: // // CONDITION_HAGER estimates the L1 condition number of a matrix. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 12 April 2012 // // Author: // // John Burkardt // // Reference: // // William Hager, // Condition Estimates, // SIAM Journal on Scientific and Statistical Computing, // Volume 5, Number 2, June 1984, pages 311-316. // // Parameters: // // Input, int N, the dimension of the matrix. // // Input, double A[N*N], the matrix. // // Output, double CONDITION_HAGER, the estimated L1 condition. // { double *a_lu; double *b; double c1; double c2; double cond; int i; int i1; int i2; int info; int job; int *pivot; i1 = -1; c1 = 0.0; // // Factor the matrix. // a_lu = r8mat_copy_new ( n, n, a ); pivot = new int[n]; info = r8ge_fa ( n, a_lu, pivot ); b = new double[n]; for ( i = 0; i < n; i++ ) { b[i] = 1.0 / ( double ) ( n ); } while ( 1 ) { job = 0; r8ge_sl ( n, a_lu, pivot, b, job ); c2 = r8vec_norm_l1 ( n, b ); for ( i = 0; i < n; i++ ) { b[i] = r8_sign ( b[i] ); } job = 1; r8ge_sl ( n, a_lu, pivot, b, job ); i2 = r8vec_max_abs_index ( n, b ); if ( 0 <= i1 ) { if ( i1 == i2 || c2 <= c1 ) { break; } } i1 = i2; c1 = c2; for ( i = 0; i < n; i++ ) { b[i] = 0.0; } b[i1] = 1.0; } cond = c2 * r8mat_norm_l1 ( n, n, a ); delete [] a_lu; delete [] b; delete [] pivot; return cond; } //****************************************************************************80 double condition_linpack ( int n, double a[] ) //****************************************************************************80 // // Purpose: // // CONDITION_LINPACK estimates the L1 condition number. // // Discussion: // // The R8GE storage format is used for a "general" M by N matrix. // A physical storage space is made for each logical entry. The two // dimensional logical array is mapped to a vector, in which storage is // by columns. // // For the system A * X = B, relative perturbations in A and B // of size EPSILON may cause relative perturbations in X of size // EPSILON * COND. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 09 April 2012 // // Author: // // Original FORTRAN77 version by Dongarra, Bunch, Moler, Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Jim Bunch, Cleve Moler, Pete Stewart, // LINPACK User's Guide, // SIAM, 1979, // ISBN13: 978-0-898711-72-1, // LC: QA214.L56. // // Parameters: // // Input, int N, the order of the matrix A. // // Input/output, double A[N*N]. On input, a matrix to be factored. // On output, the LU factorization of the matrix. // // Output, double CONDITION_LINPACK, the estimated L1 condition. // { double anorm; double cond; double ek; int i; int info; int j; int k; int l; int *pivot; double s; double sm; double t; double wk; double wkm; double ynorm; double *z; // // Compute the L1 norm of A. // anorm = 0.0; for ( j = 0; j < n; j++ ) { s = 0.0; for ( i = 0; i < n; i++ ) { s = s + r8_abs ( a[i+j*n] ); } anorm = r8_max ( anorm, s ); } // // Compute the LU factorization. // pivot = new int[n]; info = r8ge_fa ( n, a, pivot ); if ( info != 0 ) { delete [] pivot; cond = 0.0; return cond; } // // COND = norm(A) * (estimate of norm(inverse(A))) // // estimate of norm(inverse(A)) = norm(Z) / norm(Y) // // where // A * Z = Y // and // A' * Y = E // // The components of E are chosen to cause maximum local growth in the // elements of W, where U'*W = E. The vectors are frequently rescaled // to avoid overflow. // // Solve U' * W = E. // ek = 1.0; z = new double[n]; for ( i = 0; i < n; i++ ) { z[i] = 0.0; } for ( k = 0; k < n; k++ ) { if ( z[k] != 0.0 ) { ek = - r8_sign2 ( ek, z[k] ); } if ( r8_abs ( a[k+k*n] ) < r8_abs ( ek - z[k] ) ) { s = r8_abs ( a[k+k*n] ) / r8_abs ( ek - z[k] ); for ( i = 0; i < n; i++ ) { z[i] = s * z[i]; } ek = s * ek; } wk = ek - z[k]; wkm = -ek - z[k]; s = r8_abs ( wk ); sm = r8_abs ( wkm ); if ( a[k+k*n] != 0.0 ) { wk = wk / a[k+k*n]; wkm = wkm / a[k+k*n]; } else { wk = 1.0; wkm = 1.0; } if ( k + 2 <= n ) { for ( j = k+1; j < n; j++ ) { sm = sm + r8_abs ( z[j] + wkm * a[k+j*n] ); z[j] = z[j] + wk * a[k+j*n]; s = s + r8_abs ( z[j] ); } if ( s < sm ) { t = wkm - wk; wk = wkm; for ( j = k+1; j < n; j++ ) { z[j] = z[j] + t * a[k+j*n]; } } } z[k] = wk; } s = 0.0; for ( i = 0; i < n; i++ ) { s = s + r8_abs ( z[i] ); } for ( i = 0; i < n; i++ ) { z[i] = z[i] / s; } // // Solve L' * Y = W // for ( k = n-1; 0 <= k; k-- ) { for ( i = k+1; i < n; i++ ) { z[k] = z[k] + z[i] * a[i+k*n]; } t = r8_abs ( z[k] ); if ( 1.0 < t ) { for ( i = 0; i < n; i++ ) { z[i] = z[i] / t; } } l = pivot[k] - 1; t = z[l]; z[l] = z[k]; z[k] = t; } t = 0.0; for ( i = 0; i < n; i++ ) { t = t + r8_abs ( z[i] ); } for ( i = 0; i < n; i++ ) { z[i] = z[i] / t; } ynorm = 1.0; // // Solve L * V = Y. // for ( k = 0; k < n; k++ ) { l = pivot[k] - 1; t = z[l]; z[l] = z[k]; z[k] = t; for ( i = k+1; i < n; i++ ) { z[i] = z[i] + t * a[i+k*n]; } t = r8_abs ( z[k] ); if ( 1.0 < t ) { ynorm = ynorm / t; for ( i = 0; i < n; i++ ) { z[i] = z[i] / t; } } } s = 0.0; for ( i = 0; i < n; i++ ) { s = s + r8_abs ( z[i] ); } for ( i = 0; i < n; i++ ) { z[i] = z[i] / s; } ynorm = ynorm / s; // // Solve U * Z = V. // for ( k = n-1; 0 <= k; k-- ) { if ( r8_abs ( a[k+k*n] ) < r8_abs ( z[k] ) ) { s = r8_abs ( a[k+k*n] ) / r8_abs ( z[k] ); for ( i = 0; i < n; i++ ) { z[i] = s * z[i]; } ynorm = s * ynorm; } if ( a[k+k*n] != 0.0 ) { z[k] = z[k] / a[k+k*n]; } else { z[k] = 1.0; } for ( i = 0; i < k; i++ ) { z[i] = z[i] - a[i+k*n] * z[k]; } } // // Normalize Z in the L1 norm. // s = 0.0; for ( i = 0; i < n; i++ ) { s = s + r8_abs ( z[i] ); } s = 1.0 / s; for ( i = 0; i < n; i++ ) { z[i] = s * z[i]; } ynorm = s * ynorm; cond = anorm / ynorm; delete [] pivot; delete [] z; return cond; } //****************************************************************************80 double condition_sample1 ( int n, double a[], int m ) //****************************************************************************80 // // Purpose: // // CONDITION_SAMPLE1 estimates the L1 condition number of a matrix. // // Discussion: // // A naive sampling method is used. // // Only "forward" sampling is used, that is, we only look at results // of the form y=A*x. // // Presumably, solving systems A*y=x would give us a better idea of // the inverse matrix. // // Moreover, a power sequence y1 = A*x, y2 = A*y1, ... and the same for // the inverse might work better too. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 09 April 2012 // // Author: // // John Burkardt // // Parameters: // // Input, int N, the dimension of the matrix. // // Input, double A[N*N], the matrix. // // Input, int M, the number of samples to use. // // Output, double CONDITION_SAMPLE1, the estimated L1 condition. // { double a_norm; double ainv_norm; double *ax; double ax_norm; double cond; int i; int seed; double *x; double x_norm; a_norm = 0.0; ainv_norm = 0.0; seed = 123456789; for ( i = 1; i <= m; i++ ) { x = r8vec_uniform_unit_new ( n, seed ); x_norm = r8vec_norm_l1 ( n, x ); ax = r8mat_mv_new ( n, n, a, x ); ax_norm = r8vec_norm_l1 ( n, ax ); if ( ax_norm == 0.0 ) { cond = 0.0; return cond; } a_norm = r8_max ( a_norm, ax_norm / x_norm ); ainv_norm = r8_max ( ainv_norm, x_norm / ax_norm ); delete [] ax; delete [] x; } cond = a_norm * ainv_norm; return cond; } //****************************************************************************80 double *conex1 ( double alpha ) //****************************************************************************80 // // Purpose: // // CONEX1 returns the CONEX1 matrix. // // Discussion: // // The CONEX1 matrix is a counterexample to the LINPACK condition // number estimator RCOND available in the LINPACK routine DGECO. // // Formula: // // 1 -1 -2*ALPHA 0 // 0 1 ALPHA -ALPHA // 0 1 1+ALPHA -1-ALPHA // 0 0 0 ALPHA // // Example: // // ALPHA = 100 // // 1 -1 -200 0 // 0 1 100 -100 // 0 1 101 -101 // 0 0 0 100 // // Properties: // // A is generally not symmetric: A' /= A. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 28 August 2008 // // Author: // // John Burkardt // // Reference: // // Alan Cline, RK Rew, // A set of counterexamples to three condition number estimators, // SIAM Journal on Scientific and Statistical Computing, // Volume 4, 1983, pages 602-611. // // Parameters: // // Input, double ALPHA, the scalar defining A. // A common value is 100.0. // // Output, double CONEX1[4*4], the matrix. // { double *a; int n = 4; a = new double[n*n]; a[0+0*n] = 1.0; a[1+0*n] = 0.0; a[2+0*n] = 0.0; a[3+0*n] = 0.0; a[0+1*n] = -1.0; a[1+1*n] = 1.0; a[2+1*n] = 1.0; a[3+1*n] = 0.0; a[0+2*n] = -2.0 * alpha; a[1+2*n] = alpha; a[2+2*n] = 1.0 + alpha; a[3+2*n] = 0.0; a[0+3*n] = 0.0; a[1+3*n] = -alpha; a[2+3*n] = -1.0 - alpha; a[3+3*n] = alpha; return a; } //****************************************************************************80 double *conex1_inverse ( double alpha ) //****************************************************************************80 // // Purpose: // // CONEX1_INVERSE returns the inverse of the CONEX1 matrix. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 01 September 2008 // // Author: // // John Burkardt // // Parameters: // // Input, double ALPHA, the scalar defining A. // // Output, double CONEX1_INVERSE[4*4], the matrix. // { double *a; int n = 4; a = new double[n*n]; a[0+0*n] = 1.0; a[1+0*n] = 0.0; a[2+0*n] = 0.0; a[3+0*n] = 0.0; a[0+1*n] = 1.0 - alpha; a[1+1*n] = 1.0 + alpha; a[2+1*n] = -1.0; a[3+1*n] = 0.0; a[0+2*n] = alpha; a[1+2*n] = - alpha; a[2+2*n] = 1.0; a[3+2*n] = 0.0; a[0+3*n] = 2.0; a[1+3*n] = 0.0; a[2+3*n] = 1.0 / alpha; a[3+3*n] = 1.0 / alpha; return a; } //****************************************************************************80 double *conex2 ( double alpha ) //****************************************************************************80 // // Purpose: // // CONEX2 returns the CONEX2 matrix. // // Formula: // // 1 1-1/ALPHA^2 -2 // 0 1/ALPHA -1/ALPHA // 0 0 1 // // Example: // // ALPHA = 100 // // 1 0.9999 -2 // 0 0.01 -0.01 // 0 0 1 // // Properties: // // A is generally not symmetric: A' /= A. // // A is upper triangular. // // det ( A ) = 1 / ALPHA. // // LAMBDA = ( 1, 1/ALPHA, 1 ) // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 01 September 2008 // // Author: // // John Burkardt // // Reference: // // Alan Cline, RK Rew, // A set of counterexamples to three condition number estimators, // SIAM Journal on Scientific and Statistical Computing, // Volume 4, 1983, pages 602-611. // // Parameters: // // Input, double ALPHA, the scalar defining A. // A common value is 100.0. ALPHA must not be zero. // // Output, double CONEX2[3*3], the matrix. // { double *a; int n = 3; a = new double[n*n]; if ( alpha == 0.0 ) { cerr << "\n"; cerr << "CONEX2 - Fatal error!\n"; cerr << " The input value of ALPHA was zero.\n"; exit ( 1 ); } a[0+0*n] = 1.0; a[1+0*n] = 0.0; a[2+0*n] = 0.0; a[0+1*n] = ( alpha - 1.0 ) * ( alpha + 1.0 ) / alpha / alpha; a[1+1*n] = 1.0 / alpha; a[2+1*n] = 0.0; a[0+2*n] = -2.0; a[1+2*n] = -1.0 / alpha; a[2+2*n] = 1.0; return a; } //****************************************************************************80 double *conex2_inverse ( double alpha ) //****************************************************************************80 // // Purpose: // // CONEX2_INVERSE returns the inverse of the CONEX2 matrix. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 01 September 2008 // // Author: // // John Burkardt // // Parameters: // // Input, double ALPHA, the scalar defining A. // A common value is 100.0. ALPHA must not be zero. // // Output, double CONEX2_INVERSE[3*3], the matrix. // { double *a; int n = 3; a = new double[n*n]; if ( alpha == 0.0 ) { cerr << "\n"; cerr << "CONEX2_INVERSE - Fatal error!\n"; cerr << " The input value of ALPHA was zero.\n"; exit ( 1 ); } a[0+0*n] = 1.0; a[1+0*n] = 0.0; a[2+0*n] = 0.0; a[0+1*n] = ( 1.0 - alpha ) * ( 1.0 + alpha ) / alpha; a[1+1*n] = alpha; a[2+1*n] = 0.0; a[0+2*n] = ( 1.0 + alpha * alpha ) / alpha / alpha; a[1+2*n] = 1.0; a[2+2*n] = 1.0; return a; } //****************************************************************************80 double *conex3 ( int n ) //****************************************************************************80 // // Purpose: // // CONEX3 returns the CONEX3 matrix. // // Formula: // // if ( I = J and I < N ) // A(I,J) = 1.0 for 1<=I