# include # include # include # include # include # include # include "condition.h" # include "r8lib.h" /******************************************************************************/ double *combin ( double alpha, double beta, int n ) /******************************************************************************/ /* 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 MIT 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 = ( double * ) malloc ( n * n * sizeof ( double ) ); 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; } /******************************************************************************/ double *combin_inverse ( double alpha, double beta, int n ) /******************************************************************************/ /* 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 MIT 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 ) { fprintf ( stderr, "\n" ); fprintf ( stderr, "COMBIN_INVERSE - Fatal error!\n" ); fprintf ( stderr, " The entries of the matrix are undefined\n" ); fprintf ( stderr, " because ALPHA = 0.\n" ); exit ( 1 ); } else if ( alpha + n * beta == 0.0 ) { fprintf ( stderr, "\n" ); fprintf ( stderr, "COMBIN_INVERSE - Fatal error!\n" ); fprintf ( stderr, " The entries of the matrix are undefined\n" ); fprintf ( stderr, " because ALPHA+N*BETA is zero.\n" ); exit ( 1 ); } a = ( double * ) malloc ( n * n * sizeof ( double ) ); 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; } /******************************************************************************/ double condition_hager ( int n, double a[] ) /******************************************************************************/ /* Purpose: CONDITION_HAGER estimates the L1 condition number of a matrix. Licensing: This code is distributed under the MIT 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 job; int *pivot; i1 = -1; c1 = 0.0; /* Factor the matrix. */ a_lu = r8mat_copy_new ( n, n, a ); pivot = ( int * ) malloc ( n * sizeof ( int ) ); r8ge_fa ( n, a_lu, pivot ); b = ( double * ) malloc ( n * sizeof ( double ) ); 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 ); free ( a_lu ); free ( b ); free ( pivot ); return cond; } /******************************************************************************/ double condition_linpack ( int n, double a[] ) /******************************************************************************/ /* 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 MIT 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 + fabs ( a[i+j*n] ); } anorm = fmax ( anorm, s ); } /* Compute the LU factorization. */ pivot = ( int * ) malloc ( n * sizeof ( int ) ); info = r8ge_fa ( n, a, pivot ); if ( info != 0 ) { free ( 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 = ( double * ) malloc ( n * sizeof ( double ) ); 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 ( fabs ( a[k+k*n] ) < fabs ( ek - z[k] ) ) { s = fabs ( a[k+k*n] ) / fabs ( 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 = fabs ( wk ); sm = fabs ( 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 + fabs ( z[j] + wkm * a[k+j*n] ); z[j] = z[j] + wk * a[k+j*n]; s = s + fabs ( 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 + fabs ( 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 = fabs ( 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 + fabs ( 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 = fabs ( 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 + fabs ( 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 ( fabs ( a[k+k*n] ) < fabs ( z[k] ) ) { s = fabs ( a[k+k*n] ) / fabs ( 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 + fabs ( z[i] ); } s = 1.0 / s; for ( i = 0; i < n; i++ ) { z[i] = s * z[i]; } ynorm = s * ynorm; cond = anorm / ynorm; free ( pivot ); free ( z ); return cond; } /******************************************************************************/ double condition_sample1 ( int n, double a[], int m ) /******************************************************************************/ /* 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 MIT 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 = fmax ( a_norm, ax_norm / x_norm ); ainv_norm = fmax ( ainv_norm, x_norm / ax_norm ); free ( ax ); free ( x ); } cond = a_norm * ainv_norm; return cond; } /******************************************************************************/ double *conex1 ( double alpha ) /******************************************************************************/ /* 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 MIT 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 = ( double * ) malloc ( n * n * sizeof ( double ) ); 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; } /******************************************************************************/ double *conex1_inverse ( double alpha ) /******************************************************************************/ /* Purpose: CONEX1_INVERSE returns the inverse of the CONEX1 matrix. Licensing: This code is distributed under the MIT 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 = ( double * ) malloc ( n * n * sizeof ( double ) ); 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; } /******************************************************************************/ double *conex2 ( double alpha ) /******************************************************************************/ /* 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 MIT 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 = ( double * ) malloc ( n * n * sizeof ( double ) ); if ( alpha == 0.0 ) { fprintf ( stderr, "\n" ); fprintf ( stderr, "CONEX2 - Fatal error!\n" ); fprintf ( stderr, " 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; } /******************************************************************************/ double *conex2_inverse ( double alpha ) /******************************************************************************/ /* Purpose: CONEX2_INVERSE returns the inverse of the CONEX2 matrix. Licensing: This code is distributed under the MIT 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 = ( double * ) malloc ( n * n * sizeof ( double ) ); if ( alpha == 0.0 ) { fprintf ( stderr, "\n" ); fprintf ( stderr, "CONEX2_INVERSE - Fatal error!\n" ); fprintf ( stderr, " 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; } /******************************************************************************/ double *conex3 ( int n ) /******************************************************************************/ /* Purpose: CONEX3 returns the CONEX3 matrix. Formula: if ( I = J and I < N ) A(I,J) = 1.0 for 1<=I