public static void r8po_sl(double[] a, int lda, int n, ref double[] b, int aIndex = 0, int bIndex = 0) //****************************************************************************80 // // Purpose: // // R8PO_SL solves a linear system factored by R8PO_FA. // // Discussion: // // A division by zero will occur if the input factor contains // a zero on the diagonal. Technically this indicates // singularity but it is usually caused by improper subroutine // arguments. It will not occur if the subroutines are called // correctly and INFO == 0. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 May 2005 // // Author: // // FORTRAN77 original version by Dongarra, Moler, Bunch, Stewart. // C++ version by John Burkardt. // // Reference: // // Dongarra, Moler, Bunch and Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input, double A[LDA*N], the output from R8PO_FA. // // Input, int LDA, the leading dimension of the array A. // // Input, int N, the order of the matrix. // // Input/output, double B[N]. On input, the right hand side. // On output, the solution. // { int k; double t; // // Solve R' * Y = B. // for (k = 1; k <= n; k++) { t = BLAS1D.ddot(k - 1, a, 1, b, 1, aIndex + 0 + (k - 1) * lda, bIndex); b[bIndex + k - 1] = (b[bIndex + k - 1] - t) / a[aIndex + k - 1 + (k - 1) * lda]; } // // Solve R * X = Y. // for (k = n; 1 <= k; k--) { b[bIndex + k - 1] /= a[aIndex + k - 1 + (k - 1) * lda]; t = -b[bIndex + k - 1]; BLAS1D.daxpy(k - 1, t, a, 1, ref b, 1, aIndex + 0 + (k - 1) * lda, bIndex); } }
public static int r8po_fa(ref double[] a, int lda, int n) //****************************************************************************80 // // Purpose: // // R8PO_FA factors a real symmetric positive definite matrix. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 May 2005 // // Author: // // FORTRAN77 original version by Dongarra, Moler, Bunch, Stewart. // C++ version by John Burkardt. // // Reference: // // Dongarra, Moler, Bunch and Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input/output, double A[LDA*N]. On input, the symmetric matrix // to be factored. Only the diagonal and upper triangle are used. // On output, an upper triangular matrix R so that A = R'*R // where R' is the transpose. The strict lower triangle is unaltered. // If INFO /= 0, the factorization is not complete. // // Input, int LDA, the leading dimension of the array A. // // Input, int N, the order of the matrix. // // Output, int R8PO_FA, error flag. // 0, for normal return. // K, signals an error condition. The leading minor of order K is not // positive definite. // { int info; int j; for (j = 1; j <= n; j++) { double s = 0.0; int k; for (k = 1; k <= j - 1; k++) { double t = a[k - 1 + (j - 1) * lda] - BLAS1D.ddot(k - 1, a, 1, a, 1, +0 + (k - 1) * lda, +0 + (j - 1) * lda); t /= a[k - 1 + (k - 1) * lda]; a[k - 1 + (j - 1) * lda] = t; s += t * t; } s = a[j - 1 + (j - 1) * lda] - s; switch (s) { case <= 0.0: info = j; return(info); default: a[j - 1 + (j - 1) * lda] = Math.Sqrt(s); break; } } info = 0; return(info); }
public static double dpoco(ref double[] a, int lda, int n, ref double[] z) //****************************************************************************80 // // Purpose: // // DPOCO factors a real symmetric positive definite matrix and estimates its condition. // // Discussion: // // If RCOND is not needed, DPOFA is slightly faster. // // To solve A*X = B, follow DPOCO by DPOSL. // // To compute inverse(A)*C, follow DPOCO by DPOSL. // // To compute determinant(A), follow DPOCO by DPODI. // // To compute inverse(A), follow DPOCO by DPODI. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 06 June 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input/output, double A[LDA*N]. On input, the symmetric // matrix to be factored. Only the diagonal and upper triangle are used. // On output, an upper triangular matrix R so that A = R'*R where R' // is the transpose. The strict lower triangle is unaltered. // If INFO /= 0, the factorization is not complete. // // Input, int LDA, the leading dimension of the array A. // // Input, int N, the order of the matrix. // // Output, double Z[N], a work vector whose contents are usually // unimportant. If A is close to a singular matrix, then Z is an // approximate null vector in the sense that // norm(A*Z) = RCOND * norm(A) * norm(Z). // If INFO /= 0, Z is unchanged. // // Output, double DPOCO, an estimate of the reciprocal // condition of A. For the system A*X = B, relative perturbations in // A and B of size EPSILON may cause relative perturbations in X of // size EPSILON/RCOND. If RCOND is so small that the logical expression // 1.0D+00 + RCOND == 1.0D+00 // is true, then A may be singular to working precision. In particular, // RCOND is zero if exact singularity is detected or the estimate underflows. // { int i; int j; int k; double rcond; double s; double t; // // Find norm of A using only upper half. // for (j = 1; j <= n; j++) { z[j - 1] = BLAS1D.dasum(j, a, 1, index: +0 + (j - 1) * lda); for (i = 1; i <= j - 1; i++) { z[i - 1] += Math.Abs(a[i - 1 + (j - 1) * lda]); } } double anorm = 0.0; for (i = 1; i <= n; i++) { anorm = Math.Max(anorm, z[i - 1]); } // // Factor. // int info = DPOFA.dpofa(ref a, lda, n); if (info != 0) { rcond = 0.0; return(rcond); } // // RCOND = 1/(norm(A)*(estimate of norm(inverse(A)))). // // Estimate = 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 R'*W = E. // // The vectors are frequently rescaled to avoid overflow. // // Solve R' * W = E. // double ek = 1.0; for (i = 1; i <= n; i++) { z[i - 1] = 0.0; } for (k = 1; k <= n; k++) { if (z[k - 1] != 0.0) { ek *= typeMethods.r8_sign(-z[k - 1]); } if (a[k - 1 + (k - 1) * lda] < Math.Abs(ek - z[k - 1])) { s = a[k - 1 + (k - 1) * lda] / Math.Abs(ek - z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ek = s * ek; } double wk = ek - z[k - 1]; double wkm = -ek - z[k - 1]; s = Math.Abs(wk); double sm = Math.Abs(wkm); wk /= a[k - 1 + (k - 1) * lda]; wkm /= a[k - 1 + (k - 1) * lda]; if (k + 1 <= n) { for (j = k + 1; j <= n; j++) { sm += Math.Abs(z[j - 1] + wkm * a[k - 1 + (j - 1) * lda]); z[j - 1] += wk * a[k - 1 + (j - 1) * lda]; s += Math.Abs(z[j - 1]); } if (s < sm) { t = wkm - wk; wk = wkm; for (j = k + 1; j <= n; j++) { z[j - 1] += t * a[k - 1 + (j - 1) * lda]; } } } z[k - 1] = wk; } s = BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] /= s; } // // Solve R * Y = W. // for (k = n; 1 <= k; k--) { if (a[k - 1 + (k - 1) * lda] < Math.Abs(z[k - 1])) { s = a[k - 1 + (k - 1) * lda] / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } } z[k - 1] /= a[k - 1 + (k - 1) * lda]; t = -z[k - 1]; BLAS1D.daxpy(k - 1, t, a, 1, ref z, 1, xIndex: +0 + (k - 1) * lda); } s = BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] /= s; } double ynorm = 1.0; // // Solve R' * V = Y. // for (k = 1; k <= n; k++) { z[k - 1] -= BLAS1D.ddot(k - 1, a, 1, z, 1, xIndex: +0 + (k - 1) * lda); if (a[k - 1 + (k - 1) * lda] < Math.Abs(z[k - 1])) { s = a[k - 1 + (k - 1) * lda] / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; } z[k - 1] /= a[k - 1 + (k - 1) * lda]; } s = 1.0 / BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; // // Solve R * Z = V. // for (k = n; 1 <= k; k--) { if (a[k - 1 + (k - 1) * lda] < Math.Abs(z[k - 1])) { s = a[k - 1 + (k - 1) * lda] / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; } z[k - 1] /= a[k - 1 + (k - 1) * lda]; t = -z[k - 1]; BLAS1D.daxpy(k - 1, t, a, 1, ref z, 1, xIndex: +0 + (k - 1) * lda); } // // Make ZNORM = 1.0. // s = 1.0 / BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; if (anorm != 0.0) { rcond = ynorm / anorm; } else { rcond = 0.0; } return(rcond); }
public static double dgeco(ref double[] a, int lda, int n, ref int[] ipvt, ref double[] z) //****************************************************************************80 // // Purpose: // // DGECO factors a real matrix and estimates its condition number. // // Discussion: // // If RCOND is not needed, DGEFA is slightly faster. // // To solve A * X = B, follow DGECO by DGESL. // // To compute inverse ( A ) * C, follow DGECO by DGESL. // // To compute determinant ( A ), follow DGECO by DGEDI. // // To compute inverse ( A ), follow DGECO by DGEDI. // // For the system A * X = B, relative perturbations in A and B // of size EPSILON may cause relative perturbations in X of size // EPSILON/RCOND. // // If RCOND is so small that the logical expression // 1.0D+00 + RCOND == 1.0D+00 // is true, then A may be singular to working precision. In particular, // RCOND is zero if exact singularity is detected or the estimate // underflows. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 25 May 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input/output, double A[LDA*N]. On input, a matrix to be // factored. On output, the LU factorization of the matrix. // // Input, int LDA, the leading dimension of the array A. // // Input, int N, the order of the matrix A. // // Output, int IPVT[N], the pivot indices. // // Output, double Z[N], a work vector whose contents are usually // unimportant. If A is close to a singular matrix, then Z is an // approximate null vector in the sense that // norm ( A * Z ) = RCOND * norm ( A ) * norm ( Z ). // // Output, double DGECO, the value of RCOND, an estimate // of the reciprocal condition number of A. // { int i; int j; int k; int l; double rcond; double s; double t; // // Compute the L1 norm of A. // double anorm = 0.0; for (j = 1; j <= n; j++) { anorm = Math.Max(anorm, BLAS1D.dasum(n, a, 1, index: +0 + (j - 1) * lda)); } // // Compute the LU factorization. // DGEFA.dgefa(ref a, lda, n, ref ipvt); // // RCOND = 1 / ( 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. // double ek = 1.0; for (i = 1; i <= n; i++) { z[i - 1] = 0.0; } for (k = 1; k <= n; k++) { if (z[k - 1] != 0.0) { ek *= typeMethods.r8_sign(-z[k - 1]); } if (Math.Abs(a[k - 1 + (k - 1) * lda]) < Math.Abs(ek - z[k - 1])) { s = Math.Abs(a[k - 1 + (k - 1) * lda]) / Math.Abs(ek - z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ek = s * ek; } double wk = ek - z[k - 1]; double wkm = -ek - z[k - 1]; s = Math.Abs(wk); double sm = Math.Abs(wkm); if (a[k - 1 + (k - 1) * lda] != 0.0) { wk /= a[k - 1 + (k - 1) * lda]; wkm /= a[k - 1 + (k - 1) * lda]; } else { wk = 1.0; wkm = 1.0; } if (k + 1 <= n) { for (j = k + 1; j <= n; j++) { sm += Math.Abs(z[j - 1] + wkm * a[k - 1 + (j - 1) * lda]); z[j - 1] += wk * a[k - 1 + (j - 1) * lda]; s += Math.Abs(z[j - 1]); } if (s < sm) { t = wkm - wk; wk = wkm; for (i = k + 1; i <= n; i++) { z[i - 1] += t * a[k - 1 + (i - 1) * lda]; } } } z[k - 1] = wk; } t = BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] /= t; } // // Solve L' * Y = W // for (k = n; 1 <= k; k--) { z[k - 1] += BLAS1D.ddot(n - k, a, 1, z, 1, xIndex: +k + (k - 1) * lda, yIndex: +k); switch (Math.Abs(z[k - 1])) { case > 1.0: { t = Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] /= t; } break; } } l = ipvt[k - 1]; t = z[l - 1]; z[l - 1] = z[k - 1]; z[k - 1] = t; } t = BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] /= t; } double ynorm = 1.0; // // Solve L * V = Y. // for (k = 1; k <= n; k++) { l = ipvt[k - 1]; t = z[l - 1]; z[l - 1] = z[k - 1]; z[k - 1] = t; for (i = k + 1; i <= n; i++) { z[i - 1] += t * a[i - 1 + (k - 1) * lda]; } switch (Math.Abs(z[k - 1])) { case > 1.0: { ynorm /= Math.Abs(z[k - 1]); t = Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] /= t; } break; } } } s = BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] /= s; } ynorm /= s; // // Solve U * Z = V. // for (k = n; 1 <= k; k--) { if (Math.Abs(a[k - 1 + (k - 1) * lda]) < Math.Abs(z[k - 1])) { s = Math.Abs(a[k - 1 + (k - 1) * lda]) / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; } if (a[k - 1 + (k - 1) * lda] != 0.0) { z[k - 1] /= a[k - 1 + (k - 1) * lda]; } else { z[k - 1] = 1.0; } for (i = 1; i <= k - 1; i++) { z[i - 1] -= z[k - 1] * a[i - 1 + (k - 1) * lda]; } } // // Normalize Z in the L1 norm. // s = 1.0 / BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; if (anorm != 0.0) { rcond = ynorm / anorm; } else { rcond = 0.0; } return(rcond); }
public static int dchdd(ref double[] r, int ldr, int p, double[] x, ref double[] z, int ldz, int nz, double[] y, ref double[] rho, ref double[] c, ref double[] s) //****************************************************************************80 // // Purpose: // // DCHDD downdates an augmented Cholesky decomposition. // // Discussion: // // DCHDD can also downdate the triangular factor of an augmented QR // decomposition. // // Specifically, given an upper triangular matrix R of order P, a // row vector X, a column vector Z, and a scalar Y, DCHDD // determines an orthogonal matrix U and a scalar ZETA such that // // (R Z ) (RR ZZ) // U * ( ) = ( ), // (0 ZETA) ( X Y) // // where RR is upper triangular. // // If R and Z have been obtained from the factorization of a least squares // problem, then RR and ZZ are the factors corresponding to the problem // with the observation (X,Y) removed. In this case, if RHO // is the norm of the residual vector, then the norm of // the residual vector of the downdated problem is // sqrt ( RHO * RHO - ZETA * ZETA ). DCHDD will simultaneously downdate // several triplets (Z, Y, RHO) along with R. // // For a less terse description of what DCHDD does and how // it may be applied, see the LINPACK guide. // // The matrix U is determined as the product U(1)*...*U(P) // where U(I) is a rotation in the (P+1,I)-plane of the form // // ( C(I) -S(I) ) // ( ). // ( S(I) C(I) ) // // The rotations are chosen so that C(I) is real. // // The user is warned that a given downdating problem may be impossible // to accomplish or may produce inaccurate results. For example, this // can happen if X is near a vector whose removal will reduce the // rank of R. Beware. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 June 2009 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input/output, double R[LDR*P], the upper triangular matrix that // is to be downdated. The part of R below the diagonal is not referenced. // // Input, int LDR, the leading dimension of the array R. // LDR must be at least P. // // Input, int P, the order of the matrix R. // // Input, double X[P], the row vector that is to be removed from R. // // Input/output, double Z[LDZ*NZ], an array of NZ P-vectors // which are to be downdated along with R. // // Input, int LDZ, the leading dimension of the array Z. // LDZ must be at least P. // // Input, int NZ, the number of vectors to be downdated. // NZ may be zero, in which case Z, Y, and RHO are not referenced. // // Input, double Y[NZ], the scalars for the downdating of // the vectors Z. // // Input/output, double RHO[NZ], the norms of the residual vectors. // On output these have been changed along with R and Z. // // Output, double C[P], S[P], the cosines and sines of the // transforming rotations. // // Output, int DCHDD, return flag. // 0, the entire downdating was successful. // -1, if R could not be downdated. In this case, all quantities // are left unaltered. // 1, if some RHO could not be downdated. The offending RHO's are // set to -1. // { int i; int ii; int j; // // Solve R' * A = X, placing the result in the array S. // int info = 0; s[0] = x[0] / r[0 + 0 * ldr]; for (j = 2; j <= p; j++) { s[j - 1] = x[j - 1] - BLAS1D.ddot(j - 1, r, 1, s, 1, xIndex: +0 + (j - 1) * ldr); s[j - 1] /= r[j - 1 + (j - 1) * ldr]; } double norm = BLAS1D.dnrm2(p, s, 1); switch (norm) { case >= 1.0: info = -1; return(info); } double alpha = Math.Sqrt(1.0 - norm * norm); // // Determine the transformations. // for (ii = 1; ii <= p; ii++) { i = p - ii + 1; double scale = alpha + Math.Abs(s[i - 1]); double a = alpha / scale; double b = s[i - 1] / scale; norm = Math.Sqrt(a * a + b * b); c[i - 1] = a / norm; s[i - 1] = b / norm; alpha = scale * norm; } // // Apply the transformations to R. // for (j = 1; j <= p; j++) { double xx = 0.0; for (ii = 1; ii <= j; ii++) { i = j - ii + 1; double t = c[i - 1] * xx + s[i - 1] * r[i - 1 + (j - 1) * ldr]; r[i - 1 + (j - 1) * ldr] = c[i - 1] * r[i - 1 + (j - 1) * ldr] - s[i - 1] * xx; xx = t; } } // // If required, downdate Z and RHO. // for (j = 1; j <= nz; j++) { double zeta = y[j - 1]; for (i = 1; i <= p; i++) { z[i - 1 + (j - 1) * ldz] = (z[i - 1 + (j - 1) * ldz] - s[i - 1] * zeta) / c[i - 1]; zeta = c[i - 1] * zeta - s[i - 1] * z[i - 1 + (j - 1) * ldz]; } double azeta = Math.Abs(zeta); if (rho[j - 1] < azeta) { info = 1; rho[j - 1] = -1.0; } else { rho[j - 1] *= Math.Sqrt(1.0 - Math.Pow(azeta / rho[j - 1], 2)); } } return(info); }
private static void ddot_test() //****************************************************************************80 // // Purpose: // // DDOT_TEST demonstrates DDOT. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 15 May 2006 // // Author: // // John Burkardt // { const int N = 5; const int LDA = 10; const int LDB = 7; const int LDC = 6; double[] a = new double[LDA * LDA]; double[] b = new double[LDB * LDB]; double[] c = new double[LDC * LDC]; double[] x = new double[N]; double[] y = new double[N]; Console.WriteLine(""); Console.WriteLine("DDOT_TEST"); Console.WriteLine(" DDOT computes the dot product of vectors."); Console.WriteLine(""); for (int i = 0; i < N; i++) { x[i] = i + 1; } for (int i = 0; i < N; i++) { y[i] = -(double)(i + 1); } for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { a[i + j * LDA] = i + 1 + j + 1; } } for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { b[i + j * LDB] = i + 1 - (j + 1); } } double sum1 = BLAS1D.ddot(N, x, 1, y, 1); Console.WriteLine(""); Console.WriteLine(" Dot product of X and Y is " + sum1 + ""); // // To multiply a ROW of a matrix A times a vector X, we need to // specify the increment between successive entries of the row of A: // sum1 = BLAS1D.ddot(N, a, LDA, x, 1, 1); Console.WriteLine(""); Console.WriteLine(" Product of row 2 of A and X is " + sum1 + ""); // // Product of a column of A and a vector is simpler: // sum1 = BLAS1D.ddot(N, a, 1, x, 1, +0 + 1 * LDA); Console.WriteLine(""); Console.WriteLine(" Product of column 2 of A and X is " + sum1 + ""); // // Here's how matrix multiplication, c = a*b, could be done // with DDOT: // for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { c[i + j * LDC] = BLAS1D.ddot(N, a, LDA, b, 1, +i, +0 + j * LDB); } } Console.WriteLine(""); Console.WriteLine(" Matrix product computed with DDOT:"); Console.WriteLine(""); for (int i = 0; i < N; i++) { string cout = ""; for (int j = 0; j < N; j++) { cout += " " + c[i + j * LDC].ToString(CultureInfo.InvariantCulture).PadLeft(14); } Console.WriteLine(cout); } }
public static void dgesl(double[] a, int lda, int n, int[] ipvt, ref double[] b, int job) //****************************************************************************80 // // Purpose: // // DGESL solves a real general linear system A * X = B. // // Discussion: // // DGESL can solve either of the systems A * X = B or A' * X = B. // // The system matrix must have been factored by DGECO or DGEFA. // // A division by zero will occur if the input factor contains a // zero on the diagonal. Technically this indicates singularity // but it is often caused by improper arguments or improper // setting of LDA. It will not occur if the subroutines are // called correctly and if DGECO has set 0.0 < RCOND // or DGEFA has set INFO == 0. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 16 May 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input, double A[LDA*N], the output from DGECO or DGEFA. // // Input, int LDA, the leading dimension of A. // // Input, int N, the order of the matrix A. // // Input, int IPVT[N], the pivot vector from DGECO or DGEFA. // // Input/output, double B[N]. // On input, the right hand side vector. // On output, the solution vector. // // Input, int JOB. // 0, solve A * X = B; // nonzero, solve A' * X = B. // { int k; int l; double t; switch (job) { // // Solve A * X = B. // case 0: { for (k = 1; k <= n - 1; k++) { l = ipvt[k - 1]; t = b[l - 1]; if (l != k) { b[l - 1] = b[k - 1]; b[k - 1] = t; } BLAS1D.daxpy(n - k, t, a, 1, ref b, 1, +k + (k - 1) * lda, +k); } for (k = n; 1 <= k; k--) { b[k - 1] /= a[k - 1 + (k - 1) * lda]; t = -b[k - 1]; BLAS1D.daxpy(k - 1, t, a, 1, ref b, 1, +0 + (k - 1) * lda); } break; } // default: { for (k = 1; k <= n; k++) { t = BLAS1D.ddot(k - 1, a, 1, b, 1, +0 + (k - 1) * lda); b[k - 1] = (b[k - 1] - t) / a[k - 1 + (k - 1) * lda]; } for (k = n - 1; 1 <= k; k--) { b[k - 1] += BLAS1D.ddot(n - k, a, 1, b, 1, +k + (k - 1) * lda, +k); l = ipvt[k - 1]; if (l == k) { continue; } t = b[l - 1]; b[l - 1] = b[k - 1]; b[k - 1] = t; } break; } } }
public static double dgbco(ref double[] abd, int lda, int n, int ml, int mu, ref int[] ipvt, double[] z) //****************************************************************************80 // // Purpose: // // DGBCO factors a real band matrix and estimates its condition. // // Discussion: // // If RCOND is not needed, DGBFA is slightly faster. // // To solve A*X = B, follow DGBCO by DGBSL. // // To compute inverse(A)*C, follow DGBCO by DGBSL. // // To compute determinant(A), follow DGBCO by DGBDI. // // Example: // // If the original matrix is // // 11 12 13 0 0 0 // 21 22 23 24 0 0 // 0 32 33 34 35 0 // 0 0 43 44 45 46 // 0 0 0 54 55 56 // 0 0 0 0 65 66 // // then for proper band storage, // // N = 6, ML = 1, MU = 2, 5 <= LDA and ABD should contain // // * * * + + + * = not used // * * 13 24 35 46 + = used for pivoting // * 12 23 34 45 56 // 11 22 33 44 55 66 // 21 32 43 54 65 * // // Band storage: // // If A is a band matrix, the following program segment // will set up the input. // // ml = (band width below the diagonal) // mu = (band width above the diagonal) // m = ml + mu + 1 // // do j = 1, n // i1 = max ( 1, j-mu ) // i2 = min ( n, j+ml ) // do i = i1, i2 // k = i - j + m // abd(k,j) = a(i,j) // } // } // // This uses rows ML+1 through 2*ML+MU+1 of ABD. In addition, the first // ML rows in ABD are used for elements generated during the // triangularization. The total number of rows needed in ABD is // 2*ML+MU+1. The ML+MU by ML+MU upper left triangle and the ML by ML // lower right triangle are not referenced. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 07 June 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input/output, double ABD[LDA*N]. On input, the matrix in band // storage. The columns of the matrix are stored in the columns of ABD and // the diagonals of the matrix are stored in rows ML+1 through 2*ML+MU+1 // of ABD. On output, an upper triangular matrix in band storage and // the multipliers which were used to obtain it. The factorization can // be written A = L*U where L is a product of permutation and unit lower // triangular matrices and U is upper triangular. // // Input, int LDA, the leading dimension of the array ABD. // 2*ML + MU + 1 <= LDA is required. // // Input, int N, the order of the matrix. // // Input, int ML, MU, the number of diagonals below and above the // main diagonal. 0 <= ML < N, 0 <= MU < N. // // Output, int IPVT[N], the pivot indices. // // Workspace, double Z[N], a work vector whose contents are // usually unimportant. If A is close to a singular matrix, then Z is an // approximate null vector in the sense that // norm(A*Z) = RCOND * norm(A) * norm(Z). // // Output, double DGBCO, an estimate of the reciprocal condition number RCOND // of A. For the system A*X = B, relative perturbations in A and B of size // EPSILON may cause relative perturbations in X of size EPSILON/RCOND. // If RCOND is so small that the logical expression // 1.0 + RCOND == 1.0D+00 // is true, then A may be singular to working precision. In particular, // RCOND is zero if exact singularity is detected or the estimate underflows. // { int i; int j; int k; int lm; double rcond; double s; double t; // // Compute the 1-norm of A. // double anorm = 0.0; int l = ml + 1; int is_ = l + mu; for (j = 1; j <= n; j++) { anorm = Math.Max(anorm, BLAS1D.dasum(l, abd, 1, index: +is_ - 1 + (j - 1) * lda)); if (ml + 1 < is_) { is_ -= 1; } if (j <= mu) { l += 1; } if (n - ml <= j) { l -= 1; } } // // Factor. // DGBFA.dgbfa(ref abd, lda, n, ml, mu, ref ipvt); // // RCOND = 1/(norm(A)*(estimate of norm(inverse(A)))). // // Estimate = norm(Z)/norm(Y) where a*z = y and A'*Y = E. // // A' is the transpose of A. 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. // double ek = 1.0; for (i = 1; i <= n; i++) { z[i - 1] = 0.0; } int m = ml + mu + 1; int ju = 0; for (k = 1; k <= n; k++) { if (z[k - 1] != 0.0) { ek *= typeMethods.r8_sign(-z[k - 1]); } if (Math.Abs(abd[m - 1 + (k - 1) * lda]) < Math.Abs(ek - z[k - 1])) { s = Math.Abs(abd[m - 1 + (k - 1) * lda]) / Math.Abs(ek - z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ek = s * ek; } double wk = ek - z[k - 1]; double wkm = -ek - z[k - 1]; s = Math.Abs(wk); double sm = Math.Abs(wkm); if (abd[m - 1 + (k - 1) * lda] != 0.0) { wk /= abd[m - 1 + (k - 1) * lda]; wkm /= abd[m - 1 + (k - 1) * lda]; } else { wk = 1.0; wkm = 1.0; } ju = Math.Min(Math.Max(ju, mu + ipvt[k - 1]), n); int mm = m; if (k + 1 <= ju) { for (j = k + 1; j <= ju; j++) { mm -= 1; sm += Math.Abs(z[j - 1] + wkm * abd[mm - 1 + (j - 1) * lda]); z[j - 1] += wk * abd[mm - 1 + (j - 1) * lda]; s += Math.Abs(z[j - 1]); } if (s < sm) { t = wkm - wk; wk = wkm; mm = m; for (j = k + 1; j <= ju; ju++) { mm -= 1; z[j - 1] += t * abd[mm - 1 + (j - 1) * lda]; } } } z[k - 1] = wk; } s = BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] /= s; } // // Solve L' * Y = W. // for (k = n; 1 <= k; k--) { lm = Math.Min(ml, n - k); if (k < m) { z[k - 1] += BLAS1D.ddot(lm, abd, 1, z, 1, xIndex: +m + (k - 1) * lda, yIndex: +k); } switch (Math.Abs(z[k - 1])) { case > 1.0: { s = 1.0 / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } break; } } l = ipvt[k - 1]; t = z[l - 1]; z[l - 1] = z[k - 1]; z[k - 1] = t; } s = BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] /= s; } double ynorm = 1.0; // // Solve L * V = Y. // for (k = 1; k <= n; k++) { l = ipvt[k - 1]; t = z[l - 1]; z[l - 1] = z[k - 1]; z[k - 1] = t; lm = Math.Min(ml, n - k); if (k < n) { BLAS1D.daxpy(lm, t, abd, 1, ref z, 1, xIndex: +m + (k - 1) * lda, yIndex: +k); } switch (Math.Abs(z[k - 1])) { case > 1.0: { s = 1.0 / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; break; } } } s = 1.0 / BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; // // Solve U * Z = W. // for (k = n; 1 <= k; k--) { if (Math.Abs(abd[m - 1 + (k - 1) * lda]) < Math.Abs(z[k - 1])) { s = Math.Abs(abd[m - 1 + (k - 1) * lda]) / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; } if (abd[m - 1 + (k - 1) * lda] != 0.0) { z[k - 1] /= abd[m - 1 + (k - 1) * lda]; } else { z[k - 1] = 1.0; } lm = Math.Min(k, m) - 1; int la = m - lm; int lz = k - lm; t = -z[k - 1]; BLAS1D.daxpy(lm, t, abd, 1, ref z, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lz - 1); } // // Make ZNORM = 1.0. // s = 1.0 / BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; if (anorm != 0.0) { rcond = ynorm / anorm; } else { rcond = 0.0; } return(rcond); }
public static void dspsl(double[] ap, int n, int[] kpvt, ref double[] b) //****************************************************************************80 // // Purpose: // // DSPSL solves the real symmetric system factored by DSPFA. // // Discussion: // // To compute inverse(A) * C where C is a matrix with P columns: // // call dspfa ( ap, n, kpvt, info ) // // if ( info /= 0 ) go to ... // // do j = 1, p // call dspsl ( ap, n, kpvt, c(1,j) ) // end do // // A division by zero may occur if DSPCO has set RCOND == 0.0D+00 // or DSPFA has set INFO /= 0. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 25 May 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input, double AP[(N*(N+1))/2], the output from DSPFA. // // Input, int N, the order of the matrix. // // Input, int KPVT[N], the pivot vector from DSPFA. // // Input/output, double B[N]. On input, the right hand side. // On output, the solution. // { int kp; double temp; // // Loop backward applying the transformations and D inverse to B. // int k = n; int ik = n * (n - 1) / 2; while (0 < k) { int kk = ik + k; switch (kpvt[k - 1]) { case >= 0: { // // 1 x 1 pivot block. // if (k != 1) { kp = kpvt[k - 1]; // // Interchange. // if (kp != k) { temp = b[k - 1]; b[k - 1] = b[kp - 1]; b[kp - 1] = temp; } // // Apply the transformation. // BLAS1D.daxpy(k - 1, b[k - 1], ap, 1, ref b, 1, xIndex: +ik); } // // Apply D inverse. // b[k - 1] /= ap[kk - 1]; k -= 1; ik -= k; break; } default: { // // 2 x 2 pivot block. // int ikm1 = ik - (k - 1); if (k != 2) { kp = Math.Abs(kpvt[k - 1]); // // Interchange. // if (kp != k - 1) { temp = b[k - 2]; b[k - 2] = b[kp - 1]; b[kp - 1] = temp; } // // Apply the transformation. // BLAS1D.daxpy(k - 2, b[k - 1], ap, 1, ref b, 1, xIndex: +ik); BLAS1D.daxpy(k - 2, b[k - 2], ap, 1, ref b, 1, xIndex: +ikm1); } // // Apply D inverse. // int km1k = ik + k - 1; kk = ik + k; double ak = ap[kk - 1] / ap[km1k - 1]; int km1km1 = ikm1 + k - 1; double akm1 = ap[km1km1 - 1] / ap[km1k - 1]; double bk = b[k - 1] / ap[km1k - 1]; double bkm1 = b[k - 2] / ap[km1k - 1]; double denom = ak * akm1 - 1.0; b[k - 1] = (akm1 * bk - bkm1) / denom; b[k - 2] = (ak * bkm1 - bk) / denom; k -= 2; ik = ik - (k + 1) - k; break; } } } // // Loop forward applying the transformations. // k = 1; ik = 0; while (k <= n) { switch (kpvt[k - 1]) { case >= 0: { // // 1 x 1 pivot block. // if (k != 1) { // // Apply the transformation. // b[k - 1] += BLAS1D.ddot(k - 1, ap, 1, b, 1, xIndex: +ik); kp = kpvt[k - 1]; // // Interchange. // if (kp != k) { temp = b[k - 1]; b[k - 1] = b[kp - 1]; b[kp - 1] = temp; } } ik += k; k += 1; break; } default: { // // 2 x 2 pivot block. // if (k != 1) { // // Apply the transformation. // b[k - 1] += BLAS1D.ddot(k - 1, ap, 1, b, 1, xIndex: +ik); int ikp1 = ik + k; b[k] += BLAS1D.ddot(k - 1, ap, 1, b, 1, xIndex: +ikp1); kp = Math.Abs(kpvt[k - 1]); // // Interchange. // if (kp != k) { temp = b[k - 1]; b[k - 1] = b[kp - 1]; b[kp - 1] = temp; } } ik = ik + k + k + 1; k += 2; break; } } } }
public static double dppco(ref double[] ap, int n, ref double[] z) //****************************************************************************80 // // Purpose: // // DPPCO factors a real symmetric positive definite matrix in packed form. // // Discussion: // // DPPCO also estimates the condition of the matrix. // // If RCOND is not needed, DPPFA is slightly faster. // // To solve A*X = B, follow DPPCO by DPPSL. // // To compute inverse(A)*C, follow DPPCO by DPPSL. // // To compute determinant(A), follow DPPCO by DPPDI. // // To compute inverse(A), follow DPPCO by DPPDI. // // Packed storage: // // The following program segment will pack the upper triangle of // a symmetric matrix. // // k = 0 // do j = 1, n // do i = 1, j // k = k + 1 // ap[k-1] = a(i,j) // } // } // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 07 June 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input/output, double AP[N*(N+1)/2]. On input, the packed // form of a symmetric matrix A. The columns of the upper triangle are // stored sequentially in a one-dimensional array. On output, an upper // triangular matrix R, stored in packed form, so that A = R'*R. // If INFO /= 0, the factorization is not complete. // // Input, int N, the order of the matrix. // // Output, double Z[N], a work vector whose contents are usually // unimportant. If A is singular to working precision, then Z is an // approximate null vector in the sense that // norm(A*Z) = RCOND * norm(A) * norm(Z). // If INFO /= 0, Z is unchanged. // // Output, double DPPCO, an estimate of the reciprocal condition number RCOND // of A. For the system A*X = B, relative perturbations in A and B of size // EPSILON may cause relative perturbations in X of size EPSILON/RCOND. // If RCOND is so small that the logical expression // 1.0 + RCOND == 1.0D+00 // is true, then A may be singular to working precision. In particular, // RCOND is zero if exact singularity is detected or the estimate underflows. // { int i; int j; int k; double rcond; double s; double t; // // Find the norm of A. // int j1 = 1; for (j = 1; j <= n; j++) { z[j - 1] = BLAS1D.dasum(j, ap, 1, index: +j1 - 1); int ij = j1; j1 += j; for (i = 1; i <= j - 1; i++) { z[i - 1] += Math.Abs(ap[ij - 1]); ij += 1; } } double anorm = 0.0; for (i = 1; i <= n; i++) { anorm = Math.Max(anorm, z[i - 1]); } // // Factor. // int info = DPPFA.dppfa(ref ap, n); if (info != 0) { rcond = 0.0; return(rcond); } // // RCOND = 1/(norm(A)*(estimate of norm(inverse(A)))). // // Estimate = 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 R'*W = E. // // The vectors are frequently rescaled to avoid overflow. // // Solve R' * W = E. // double ek = 1.0; for (i = 1; i <= n; i++) { z[i - 1] = 0.0; } int kk = 0; for (k = 1; k <= n; k++) { kk += k; if (z[k - 1] != 0.0) { ek *= typeMethods.r8_sign(-z[k - 1]); } if (ap[kk - 1] < Math.Abs(ek - z[k - 1])) { s = ap[kk - 1] / Math.Abs(ek - z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ek = s * ek; } double wk = ek - z[k - 1]; double wkm = -ek - z[k - 1]; s = Math.Abs(wk); double sm = Math.Abs(wkm); wk /= ap[kk - 1]; wkm /= ap[kk - 1]; int kj = kk + k; if (k + 1 <= n) { for (j = k + 1; j <= n; j++) { sm += Math.Abs(z[j - 1] + wkm * ap[kj - 1]); z[j - 1] += wk * ap[kj - 1]; s += Math.Abs(z[j - 1]); kj += j; } if (s < sm) { t = wkm - wk; wk = wkm; kj = kk + k; for (j = k + 1; j <= n; j++) { z[j - 1] += t * ap[kj - 1]; kj += j; } } } z[k - 1] = wk; } s = BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] /= s; } // // Solve R * Y = W. // for (k = n; 1 <= k; k--) { if (ap[kk - 1] < Math.Abs(z[k - 1])) { s = ap[kk - 1] / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } } z[k - 1] /= ap[kk - 1]; kk -= k; t = -z[k - 1]; BLAS1D.daxpy(k - 1, t, ap, 1, ref z, 1, xIndex: +kk); } s = BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] /= s; } double ynorm = 1.0; // // Solve R' * V = Y. // for (k = 1; k <= n; k++) { z[k - 1] -= BLAS1D.ddot(k - 1, ap, 1, z, 1, xIndex: +kk); kk += k; if (ap[kk - 1] < Math.Abs(z[k - 1])) { s = ap[kk - 1] / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; } z[k - 1] /= ap[kk - 1]; } s = 1.0 / BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; // // Solve R * Z = V. // for (k = n; 1 <= k; k--) { if (ap[kk - 1] < Math.Abs(z[k - 1])) { s = ap[kk - 1] / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; } z[k - 1] /= ap[kk - 1]; kk -= k; t = -z[k - 1]; BLAS1D.daxpy(k - 1, t, ap, 1, ref z, 1, xIndex: +kk); } // // Make ZNORM = 1.0. // s = 1.0 / BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; if (anorm != 0.0) { rcond = ynorm / anorm; } else { rcond = 0.0; } return(rcond); }
public static int dtrsl(double[] t, int ldt, int n, ref double[] b, int job) //****************************************************************************80 // // Purpose: // // DTRSL solves triangular linear systems. // // Discussion: // // DTRSL can solve T * X = B or T' * X = B where T is a triangular // matrix of order N. // // Here T' denotes the transpose of the matrix T. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 19 May 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input, double T[LDT*N], the matrix of the system. The zero // elements of the matrix are not referenced, and the corresponding // elements of the array can be used to store other information. // // Input, int LDT, the leading dimension of the array T. // // Input, int N, the order of the matrix. // // Input/output, double B[N]. On input, the right hand side. // On output, the solution. // // Input, int JOB, specifies what kind of system is to be solved: // 00, solve T * X = B, T lower triangular, // 01, solve T * X = B, T upper triangular, // 10, solve T'* X = B, T lower triangular, // 11, solve T'* X = B, T upper triangular. // // Output, int DTRSL, singularity indicator. // 0, the system is nonsingular. // nonzero, the index of the first zero diagonal element of T. // { int info; int j; int jj; double temp; // // Check for zero diagonal elements. // for (j = 1; j <= n; j++) { switch (t[j - 1 + (j - 1) * ldt]) { case 0.0: info = j; return(info); } } info = 0; int kase = (job % 10) switch { // // Determine the task and go to it. // 0 => 1, _ => 2 }; if (job % 100 / 10 != 0) { kase += 2; } switch (kase) { // // Solve T * X = B for T lower triangular. // case 1: { b[0] /= t[0 + 0 * ldt]; for (j = 2; j <= n; j++) { temp = -b[j - 2]; BLAS1D.daxpy(n - j + 1, temp, t, 1, ref b, 1, xIndex: +(j - 1) + (j - 2) * ldt, yIndex: +j - 1); b[j - 1] /= t[j - 1 + (j - 1) * ldt]; } break; } // // Solve T * X = B for T upper triangular. // case 2: { b[n - 1] /= t[n - 1 + (n - 1) * ldt]; for (jj = 2; jj <= n; jj++) { j = n - jj + 1; temp = -b[j]; BLAS1D.daxpy(j, temp, t, 1, ref b, 1, xIndex: +0 + j * ldt); b[j - 1] /= t[j - 1 + (j - 1) * ldt]; } break; } // // Solve T' * X = B for T lower triangular. // case 3: { b[n - 1] /= t[n - 1 + (n - 1) * ldt]; for (jj = 2; jj <= n; jj++) { j = n - jj + 1; b[j - 1] -= BLAS1D.ddot(jj - 1, t, 1, b, 1, xIndex: +j + (j - 1) * ldt, yIndex: +j); b[j - 1] /= t[j - 1 + (j - 1) * ldt]; } break; } // // Solve T' * X = B for T upper triangular. // case 4: { b[0] /= t[0 + 0 * ldt]; for (j = 2; j <= n; j++) { b[j - 1] -= BLAS1D.ddot(j - 1, t, 1, b, 1, xIndex: +0 + (j - 1) * ldt); b[j - 1] /= t[j - 1 + (j - 1) * ldt]; } break; } } return(info); } }
public static void dsidi(ref double[] a, int lda, int n, int[] kpvt, ref double[] det, ref int[] inert, double[] work, int job) //****************************************************************************80 // // Purpose: // // DSIDI computes the determinant, inertia and inverse of a real symmetric matrix. // // Discussion: // // DSIDI uses the factors from DSIFA. // // A division by zero may occur if the inverse is requested // and DSICO has set RCOND == 0.0D+00 or DSIFA has set INFO /= 0. // // Variables not requested by JOB are not used. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 25 May 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input/output, double A(LDA,N). On input, the output from DSIFA. // On output, the upper triangle of the inverse of the original matrix, // if requested. The strict lower triangle is never referenced. // // Input, int LDA, the leading dimension of the array A. // // Input, int N, the order of the matrix. // // Input, int KPVT[N], the pivot vector from DSIFA. // // Output, double DET[2], the determinant of the original matrix, // if requested. // determinant = DET[0] * 10.0**DET[1] // with 1.0D+00 <= abs ( DET[0] ) < 10.0D+00 or DET[0] = 0.0. // // Output, int INERT(3), the inertia of the original matrix, // if requested. // INERT(1) = number of positive eigenvalues. // INERT(2) = number of negative eigenvalues. // INERT(3) = number of zero eigenvalues. // // Workspace, double WORK[N]. // // Input, int JOB, specifies the tasks. // JOB has the decimal expansion ABC where // If C /= 0, the inverse is computed, // If B /= 0, the determinant is computed, // If A /= 0, the inertia is computed. // For example, JOB = 111 gives all three. // { double d; int k; double t; bool doinv = job % 10 != 0; bool dodet = job % 100 / 10 != 0; bool doert = job % 1000 / 100 != 0; if (dodet || doert) { switch (doert) { case true: inert[0] = 0; inert[1] = 0; inert[2] = 0; break; } switch (dodet) { case true: det[0] = 1.0; det[1] = 0.0; break; } t = 0.0; for (k = 1; k <= n; k++) { d = a[k - 1 + (k - 1) * lda]; switch (kpvt[k - 1]) { // // 2 by 2 block. // // use det (d s) = (d/t * c - t) * t, t = abs ( s ) // (s c) // to avoid underflow/overflow troubles. // // Take two passes through scaling. Use T for flag. // case <= 0 when t == 0.0: t = Math.Abs(a[k - 1 + k * lda]); d = d / t * a[k + k * lda] - t; break; case <= 0: d = t; t = 0.0; break; } switch (doert) { case true: switch (d) { case > 0.0: inert[0] += 1; break; case < 0.0: inert[1] += 1; break; case 0.0: inert[2] += 1; break; } break; } switch (dodet) { case true: { det[0] *= d; if (det[0] != 0.0) { while (Math.Abs(det[0]) < 1.0) { det[0] *= 10.0; det[1] -= 1.0; } while (10.0 <= Math.Abs(det[0])) { det[0] /= 10.0; det[1] += 1.0; } } break; } } } } switch (doinv) { // // Compute inverse(A). // case true: { k = 1; while (k <= n) { int j; int kstep; switch (kpvt[k - 1]) { case >= 0: { // // 1 by 1. // a[k - 1 + (k - 1) * lda] = 1.0 / a[k - 1 + (k - 1) * lda]; switch (k) { case >= 2: { BLAS1D.dcopy(k - 1, a, 1, ref work, 1, xIndex: +0 + (k - 1) * lda); for (j = 1; j <= k - 1; j++) { a[j - 1 + (k - 1) * lda] = BLAS1D.ddot(j, a, 1, work, 1, xIndex: +0 + (j - 1) * lda); BLAS1D.daxpy(j - 1, work[j - 1], a, 1, ref a, 1, xIndex: +0 + (j - 1) * lda, yIndex: +0 + (k - 1) * lda); } a[k - 1 + (k - 1) * lda] += BLAS1D.ddot(k - 1, work, 1, a, 1, yIndex: +0 + (k - 1) * lda); break; } } kstep = 1; break; } // default: { t = Math.Abs(a[k - 1 + k * lda]); double ak = a[k - 1 + (k - 1) * lda] / t; double akp1 = a[k + k * lda] / t; double akkp1 = a[k - 1 + k * lda] / t; d = t * (ak * akp1 - 1.0); a[k - 1 + (k - 1) * lda] = akp1 / d; a[k + k * lda] = ak / d; a[k - 1 + k * lda] = -akkp1 / d; switch (k) { case >= 2: { BLAS1D.dcopy(k - 1, a, 1, ref work, 1, xIndex: +0 + k * lda); for (j = 1; j <= k - 1; j++) { a[j - 1 + k * lda] = BLAS1D.ddot(j, a, 1, work, 1, xIndex: +0 + (j - 1) * lda); BLAS1D.daxpy(j - 1, work[j - 1], a, 1, ref a, 1, xIndex: +0 + (j - 1) * lda, yIndex: +0 + k * lda); } a[k + k * lda] += BLAS1D.ddot(k - 1, work, 1, a, 1, yIndex: +0 + k * lda); a[k - 1 + k * lda] += BLAS1D.ddot(k - 1, a, 1, a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + k * lda); BLAS1D.dcopy(k - 1, a, 1, ref work, 1, xIndex: +0 + (k - 1) * lda); for (j = 1; j <= k - 1; j++) { a[j - 1 + (k - 1) * lda] = BLAS1D.ddot(j, a, 1, work, 1, xIndex: +0 + (j - 1) * lda); BLAS1D.daxpy(j - 1, work[j - 1], a, 1, ref a, 1, xIndex: +0 + (j - 1) * lda, yIndex: +0 + (k - 1) * lda); } a[k - 1 + (k - 1) * lda] += BLAS1D.ddot(k - 1, work, 1, a, 1, yIndex: +0 + (k - 1) * lda); break; } } kstep = 2; break; } } // // Swap. // int ks = Math.Abs(kpvt[k - 1]); if (ks != k) { BLAS1D.dswap(ks, ref a, 1, ref a, 1, xIndex: +0 + (ks - 1) * lda, yIndex: +0 + (k - 1) * lda); int jb; double temp; for (jb = ks; jb <= k; jb++) { j = k + ks - jb; temp = a[j - 1 + (k - 1) * lda]; a[j - 1 + (k - 1) * lda] = a[ks - 1 + (j - 1) * lda]; a[ks - 1 + (j - 1) * lda] = temp; } if (kstep != 1) { temp = a[ks - 1 + k * lda]; a[ks - 1 + k * lda] = a[k - 1 + k * lda]; a[k - 1 + k * lda] = temp; } } k += kstep; } break; } } }
public static int dpbfa(ref double[] abd, int lda, int n, int m) //****************************************************************************80 // // Purpose: // // DPBFA factors a symmetric positive definite matrix stored in band form. // // Discussion: // // DPBFA is usually called by DPBCO, but it can be called // directly with a saving in time if RCOND is not needed. // // If A is a symmetric positive definite band matrix, // the following program segment will set up the input. // // m = (band width above diagonal) // do j = 1, n // i1 = max ( 1, j-m ) // do i = i1, j // k = i-j+m+1 // abd(k,j) = a(i,j) // end do // end do // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 May 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input/output, double ABD[LDA*N]. On input, the matrix to be // factored. The columns of the upper triangle are stored in the columns // of ABD and the diagonals of the upper triangle are stored in the // rows of ABD. On output, an upper triangular matrix R, stored in band // form, so that A = R' * R. // // Input, int LDA, the leading dimension of the array ABD. // M+1 <= LDA is required. // // Input, int N, the order of the matrix. // // Input, int M, the number of diagonals above the main diagonal. // // Output, int DPBFA, error indicator. // 0, for normal return. // K, if the leading minor of order K is not positive definite. // { int info; int j; for (j = 1; j <= n; j++) { double s = 0.0; int ik = m + 1; int jk = Math.Max(j - m, 1); int mu = Math.Max(m + 2 - j, 1); int k; for (k = mu; k <= m; k++) { double t = abd[k - 1 + (j - 1) * lda] - BLAS1D.ddot(k - mu, abd, 1, abd, 1, xIndex: +ik - 1 + (jk - 1) * lda, yIndex: +mu - 1 + (j - 1) * lda); t /= abd[m + (jk - 1) * lda]; abd[k - 1 + (j - 1) * lda] = t; s += t * t; ik -= 1; jk += 1; } s = abd[m + (j - 1) * lda] - s; switch (s) { case <= 0.0: info = j; return(info); default: abd[m + (j - 1) * lda] = Math.Sqrt(s); break; } } info = 0; return(info); }
public static void dspdi(ref double[] ap, int n, int[] kpvt, ref double[] det, ref int[] inert, double[] work, int job) //****************************************************************************80 // // Purpose: // // DSPDI computes the determinant, inertia and inverse of a real symmetric matrix. // // Discussion: // // DSPDI uses the factors from DSPFA, where the matrix is stored in // packed form. // // A division by zero will occur if the inverse is requested // and DSPCO has set RCOND == 0.0D+00 or DSPFA has set INFO /= 0. // // Variables not requested by JOB are not used. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 25 May 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input/output, double AP[(N*(N+1))/2]. On input, the output from // DSPFA. On output, the upper triangle of the inverse of the original // matrix, stored in packed form, if requested. The columns of the upper // triangle are stored sequentially in a one-dimensional array. // // Input, int N, the order of the matrix. // // Input, int KPVT[N], the pivot vector from DSPFA. // // Output, double DET[2], the determinant of the original matrix, // if requested. // determinant = DET[0] * 10.0**DET[1] // with 1.0D+00 <= abs ( DET[0] ) < 10.0D+00 or DET[0] = 0.0. // // Output, int INERT[3], the inertia of the original matrix, if requested. // INERT(1) = number of positive eigenvalues. // INERT(2) = number of negative eigenvalues. // INERT(3) = number of zero eigenvalues. // // Workspace, double WORK[N]. // // Input, int JOB, has the decimal expansion ABC where: // if A /= 0, the inertia is computed, // if B /= 0, the determinant is computed, // if C /= 0, the inverse is computed. // For example, JOB = 111 gives all three. // { double d; int ik; int ikp1; int k; int kk; int kkp1; double t; bool doinv = job % 10 != 0; bool dodet = job % 100 / 10 != 0; bool doert = job % 1000 / 100 != 0; if (dodet || doert) { switch (doert) { case true: inert[0] = 0; inert[1] = 0; inert[2] = 0; break; } switch (dodet) { case true: det[0] = 1.0; det[1] = 0.0; break; } t = 0.0; ik = 0; for (k = 1; k <= n; k++) { kk = ik + k; d = ap[kk - 1]; switch (kpvt[k - 1]) { // // 2 by 2 block // use det (d s) = (d/t * c - t) * t, t = abs ( s ) // (s c) // to avoid underflow/overflow troubles. // // Take two passes through scaling. Use T for flag. // case <= 0 when t == 0.0: ikp1 = ik + k; kkp1 = ikp1 + k; t = Math.Abs(ap[kkp1 - 1]); d = d / t * ap[kkp1] - t; break; case <= 0: d = t; t = 0.0; break; } switch (doert) { case true: switch (d) { case > 0.0: inert[0] += 1; break; case < 0.0: inert[1] += 1; break; case 0.0: inert[2] += 1; break; } break; } switch (dodet) { case true: { det[0] *= d; if (det[0] != 0.0) { while (Math.Abs(det[0]) < 1.0) { det[0] *= 10.0; det[1] -= 1.0; } while (10.0 <= Math.Abs(det[0])) { det[0] /= 10.0; det[1] += 1.0; } } break; } } ik += k; } } switch (doinv) { // // Compute inverse(A). // case true: { k = 1; ik = 0; while (k <= n) { int km1 = k - 1; kk = ik + k; ikp1 = ik + k; kkp1 = ikp1 + k; int kstep; int jk; int j; int ij; switch (kpvt[k - 1]) { case >= 0: { // // 1 by 1. // ap[kk - 1] = 1.0 / ap[kk - 1]; switch (k) { case >= 2: { BLAS1D.dcopy(k - 1, ap, 1, ref work, 1, xIndex: +ik); ij = 0; for (j = 1; j <= k - 1; j++) { jk = ik + j; ap[jk - 1] = BLAS1D.ddot(j, ap, 1, work, 1, xIndex: +ij); BLAS1D.daxpy(j - 1, work[j - 1], ap, 1, ref ap, 1, xIndex: +ij, yIndex: +ik); ij += j; } ap[kk - 1] += BLAS1D.ddot(k - 1, work, 1, ap, 1, yIndex: +ik); break; } } kstep = 1; break; } default: { // // 2 by 2. // t = Math.Abs(ap[kkp1 - 1]); double ak = ap[kk - 1] / t; double akp1 = ap[kkp1] / t; double akkp1 = ap[kkp1 - 1] / t; d = t * (ak * akp1 - 1.0); ap[kk - 1] = akp1 / d; ap[kkp1] = ak / d; ap[kkp1 - 1] = -akkp1 / d; switch (km1) { case >= 1: { BLAS1D.dcopy(km1, ap, 1, ref work, 1, xIndex: +ikp1); ij = 0; for (j = 1; j <= km1; j++) { int jkp1 = ikp1 + j; ap[jkp1 - 1] = BLAS1D.ddot(j, ap, 1, work, 1, xIndex: +ij); BLAS1D.daxpy(j - 1, work[j - 1], ap, 1, ref ap, 1, xIndex: +ij, yIndex: +ikp1); ij += j; } ap[kkp1] += BLAS1D.ddot(km1, work, 1, ap, 1, yIndex: +ikp1); ap[kkp1 - 1] += BLAS1D.ddot(km1, ap, 1, ap, 1, xIndex: +ik, yIndex: +ikp1); BLAS1D.dcopy(km1, ap, 1, ref work, 1, xIndex: +ik); ij = 0; for (j = 1; j <= km1; j++) { jk = ik + j; ap[jk - 1] = BLAS1D.ddot(j, ap, 1, work, 1, xIndex: +ij); BLAS1D.daxpy(j - 1, work[j - 1], ap, 1, ref ap, 1, xIndex: +ij, yIndex: +ik); ij += j; } ap[kk - 1] += BLAS1D.ddot(km1, work, 1, ap, 1, yIndex: +ik); break; } } kstep = 2; break; } } // // Swap. // int ks = Math.Abs(kpvt[k - 1]); if (ks != k) { int iks = ks * (ks - 1) / 2; BLAS1D.dswap(ks, ref ap, 1, ref ap, 1, xIndex: +iks, yIndex: +ik); int ksj = ik + ks; double temp; int jb; for (jb = ks; jb <= k; jb++) { j = k + ks - jb; jk = ik + j; temp = ap[jk - 1]; ap[jk - 1] = ap[ksj - 1]; ap[ksj - 1] = temp; ksj -= j - 1; } if (kstep != 1) { int kskp1 = ikp1 + ks; temp = ap[kskp1 - 1]; ap[kskp1 - 1] = ap[kkp1 - 1]; ap[kkp1 - 1] = temp; } } ik += k; ik = kstep switch { 2 => ik + k + 1, _ => ik }; k += kstep; } break; } } } }
public static void dposl(double[] a, int lda, int n, ref double[] b) //****************************************************************************80 // // Purpose: // // DPOSL solves a linear system factored by DPOCO or DPOFA. // // Discussion: // // To compute inverse(A) * C where C is a matrix with P columns: // // call dpoco ( a, lda, n, rcond, z, info ) // // if ( rcond is not too small .and. info == 0 ) then // do j = 1, p // call dposl ( a, lda, n, c(1,j) ) // end do // end if // // A division by zero will occur if the input factor contains // a zero on the diagonal. Technically this indicates // singularity but it is usually caused by improper subroutine // arguments. It will not occur if the subroutines are called // correctly and INFO == 0. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 May 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input, double A[LDA*N], the output from DPOCO or DPOFA. // // Input, int LDA, the leading dimension of the array A. // // Input, int N, the order of the matrix. // // Input/output, double B[N]. On input, the right hand side. // On output, the solution. // { int k; double t; // // Solve R' * Y = B. // for (k = 1; k <= n; k++) { t = BLAS1D.ddot(k - 1, a, 1, b, 1, xIndex: +0 + (k - 1) * lda); b[k - 1] = (b[k - 1] - t) / a[k - 1 + (k - 1) * lda]; } // // Solve R * X = Y. // for (k = n; 1 <= k; k--) { b[k - 1] /= a[k - 1 + (k - 1) * lda]; t = -b[k - 1]; BLAS1D.daxpy(k - 1, t, a, 1, ref b, 1, xIndex: +0 + (k - 1) * lda); } }
public static void dgbsl(double[] abd, int lda, int n, int ml, int mu, int[] ipvt, ref double[] b, int job) //****************************************************************************80 // // Purpose: // // DGBSL solves a real banded system factored by DGBCO or DGBFA. // // Discussion: // // DGBSL can solve either A * X = B or A' * X = B. // // A division by zero will occur if the input factor contains a // zero on the diagonal. Technically this indicates singularity // but it is often caused by improper arguments or improper // setting of LDA. It will not occur if the subroutines are // called correctly and if DGBCO has set 0.0 < RCOND // or DGBFA has set INFO == 0. // // To compute inverse(A) * C where C is a matrix with P columns: // // call dgbco ( abd, lda, n, ml, mu, ipvt, rcond, z ) // // if ( rcond is too small ) then // exit // end if // // do j = 1, p // call dgbsl ( abd, lda, n, ml, mu, ipvt, c(1,j), 0 ) // end do // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 May 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input, double ABD[LDA*N], the output from DGBCO or DGBFA. // // Input, integer LDA, the leading dimension of the array ABD. // // Input, int N, the order of the matrix. // // Input, int ML, MU, the number of diagonals below and above the // main diagonal. 0 <= ML < N, 0 <= MU < N. // // Input, int IPVT[N], the pivot vector from DGBCO or DGBFA. // // Input/output, double B[N]. On input, the right hand side. // On output, the solution. // // Input, int JOB, job choice. // 0, solve A*X=B. // nonzero, solve A'*X=B. // { int k; int l; int la; int lb; int lm; double t; int m = mu + ml + 1; switch (job) { // // JOB = 0, Solve A * x = b. // // First solve L * y = b. // case 0: { switch (ml) { case > 0: { for (k = 1; k <= n - 1; k++) { lm = Math.Min(ml, n - k); l = ipvt[k - 1]; t = b[l - 1]; if (l != k) { b[l - 1] = b[k - 1]; b[k - 1] = t; } BLAS1D.daxpy(lm, t, abd, 1, ref b, 1, +m + (k - 1) * lda, k); } break; } } // // Now solve U * x = y. // for (k = n; 1 <= k; k--) { b[k - 1] /= abd[m - 1 + (k - 1) * lda]; lm = Math.Min(k, m) - 1; la = m - lm; lb = k - lm; t = -b[k - 1]; BLAS1D.daxpy(lm, t, abd, 1, ref b, 1, +la - 1 + (k - 1) * lda, +lb - 1); } break; } // default: { for (k = 1; k <= n; k++) { lm = Math.Min(k, m) - 1; la = m - lm; lb = k - lm; t = BLAS1D.ddot(lm, abd, 1, b, 1, +la - 1 + (k - 1) * lda, +lb - 1); b[k - 1] = (b[k - 1] - t) / abd[m - 1 + (k - 1) * lda]; } switch (ml) { // // Now solve L' * x = y. // case > 0: { for (k = n - 1; 1 <= k; k--) { lm = Math.Min(ml, n - k); b[k - 1] += BLAS1D.ddot(lm, abd, 1, b, 1, +m + (k - 1) * lda, +k); l = ipvt[k - 1]; if (l == k) { continue; } t = b[l - 1]; b[l - 1] = b[k - 1]; b[k - 1] = t; } break; } } break; } } }
public static int dppfa(ref double[] ap, int n) //****************************************************************************80 // // Purpose: // // DPPFA factors a real symmetric positive definite matrix in packed form. // // Discussion: // // DPPFA is usually called by DPPCO, but it can be called // directly with a saving in time if RCOND is not needed. // // Packed storage: // // The following program segment will pack the upper // triangle of a symmetric matrix. // // k = 0 // do j = 1, n // do i = 1, j // k = k + 1 // ap(k) = a(i,j) // end do // end do // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 24 May 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input/output, double AP[N*(N+1)/2]. On input, the packed // form of a symmetric matrix A. The columns of the upper triangle are // stored sequentially in a one-dimensional array. On output, an upper // triangular matrix R, stored in packed form, so that A = R'*R. // // Input, int N, the order of the matrix. // // Output, int DPPFA, error flag. // 0, for normal return. // K, if the leading minor of order K is not positive definite. // { int j; int info = 0; int jj = 0; for (j = 1; j <= n; j++) { double s = 0.0; int kj = jj; int kk = 0; int k; for (k = 1; k <= j - 1; k++) { kj += 1; double t = ap[kj - 1] - BLAS1D.ddot(k - 1, ap, 1, ap, 1, xIndex: +kk, yIndex: +jj); kk += k; t /= ap[kk - 1]; ap[kj - 1] = t; s += t * t; } jj += j; s = ap[jj - 1] - s; switch (s) { case <= 0.0: info = j; return(info); default: ap[jj - 1] = Math.Sqrt(s); break; } } return(info); }
public static void dpbsl(double[] abd, int lda, int n, int m, ref double[] b) //****************************************************************************80 // // Purpose: // // DPBSL solves a real SPD band system factored by DPBCO or DPBFA. // // Discussion: // // The matrix is assumed to be a symmetric positive definite (SPD) // band matrix. // // To compute inverse(A) * C where C is a matrix with P columns: // // call dpbco ( abd, lda, n, rcond, z, info ) // // if ( rcond is too small .or. info /= 0) go to ... // // do j = 1, p // call dpbsl ( abd, lda, n, c(1,j) ) // end do // // A division by zero will occur if the input factor contains // a zero on the diagonal. Technically this indicates // singularity but it is usually caused by improper subroutine // arguments. It will not occur if the subroutines are called // correctly and INFO == 0. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 May 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input, double ABD[LDA*N], the output from DPBCO or DPBFA. // // Input, int LDA, the leading dimension of the array ABD. // // Input, int N, the order of the matrix. // // Input, int M, the number of diagonals above the main diagonal. // // Input/output, double B[N]. On input, the right hand side. // On output, the solution. // { int k; int la; int lb; int lm; double t; // // Solve R'*Y = B. // for (k = 1; k <= n; k++) { lm = Math.Min(k - 1, m); la = m + 1 - lm; lb = k - lm; t = BLAS1D.ddot(lm, abd, 1, b, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lb - 1); b[k - 1] = (b[k - 1] - t) / abd[m + (k - 1) * lda]; } // // Solve R*X = Y. // for (k = n; 1 <= k; k--) { lm = Math.Min(k - 1, m); la = m + 1 - lm; lb = k - lm; b[k - 1] /= abd[m + (k - 1) * lda]; t = -b[k - 1]; BLAS1D.daxpy(lm, t, abd, 1, ref b, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lb - 1); } }
public static double dpbco(ref double[] abd, int lda, int n, int m, ref double[] z) //****************************************************************************80 // // Purpose: // // DPBCO factors a real symmetric positive definite banded matrix. // // Discussion: // // DPBCO also estimates the condition of the matrix. // // If RCOND is not needed, DPBFA is slightly faster. // // To solve A*X = B, follow DPBCO by DPBSL. // // To compute inverse(A)*C, follow DPBCO by DPBSL. // // To compute determinant(A), follow DPBCO by DPBDI. // // Band storage: // // If A is a symmetric positive definite band matrix, the following // program segment will set up the input. // // m = (band width above diagonal) // do j = 1, n // i1 = max (1, j-m) // do i = i1, j // k = i-j+m+1 // abd(k,j) = a(i,j) // } // } // // This uses M + 1 rows of A, except for the M by M upper left triangle, // which is ignored. // // For example, if the original matrix is // // 11 12 13 0 0 0 // 12 22 23 24 0 0 // 13 23 33 34 35 0 // 0 24 34 44 45 46 // 0 0 35 45 55 56 // 0 0 0 46 56 66 // // then N = 6, M = 2 and ABD should contain // // * * 13 24 35 46 // * 12 23 34 45 56 // 11 22 33 44 55 66 // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 07 June 2005 // // Author: // // Original FORTRAN77 version by Jack Dongarra, Cleve Moler, Jim Bunch, // Pete Stewart. // C++ version by John Burkardt. // // Reference: // // Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, // LINPACK User's Guide, // SIAM, (Society for Industrial and Applied Mathematics), // 3600 University City Science Center, // Philadelphia, PA, 19104-2688. // ISBN 0-89871-172-X // // Parameters: // // Input/output, double ABD[LDA*N]. On input, the matrix to be // factored. The columns of the upper triangle are stored in the columns // of ABD and the diagonals of the upper triangle are stored in the rows // of ABD. On output, an upper triangular matrix R, stored in band form, // so that A = R'*R. If INFO /= 0, the factorization is not complete. // // Input, int LDA, the leading dimension of the array ABD. // M+1 <= LDA is required. // // Input, int N, the order of the matrix. // // Input, int M, the number of diagonals above the main diagonal. // // Output, double Z[N], a work vector whose contents are usually // unimportant. If A is singular to working precision, then Z is an // approximate null vector in the sense that // norm(A*Z) = RCOND * norm(A) * norm(Z). // If INFO /= 0, Z is unchanged. // // Output, double DPBCO, an estimate of the reciprocal condition number // RCOND. For the system A*X = B, relative perturbations in A and B of size // EPSILON may cause relative perturbations in X of size EPSILON/RCOND. // If RCOND is so small that the logical expression // 1.0 + RCOND == 1.0D+00 // is true, then A may be singular to working precision. In particular, // RCOND is zero if exact singularity is detected or the estimate underflows. // { int i; int j; int k; int la; int lb; int lm; double rcond; double s; double t; // // Find the norm of A. // for (j = 1; j <= n; j++) { int l = Math.Min(j, m + 1); int mu = Math.Max(m + 2 - j, 1); z[j - 1] = BLAS1D.dasum(l, abd, 1, index: +mu - 1 + (j - 1) * lda); k = j - l; for (i = mu; i <= m; i++) { k += 1; z[k - 1] += Math.Abs(abd[i - 1 + (j - 1) * lda]); } } double anorm = 0.0; for (i = 1; i <= n; i++) { anorm = Math.Max(anorm, z[i - 1]); } // // Factor. // int info = DPBFA.dpbfa(ref abd, lda, n, m); if (info != 0) { rcond = 0.0; return(rcond); } // // RCOND = 1/(norm(A)*(estimate of norm(inverse(A)))). // // Estimate = 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 R'*W = E. // // The vectors are frequently rescaled to avoid overflow. // // Solve R' * W = E. // double ek = 1.0; for (i = 1; i <= n; i++) { z[i - 1] = 0.0; } for (k = 1; k <= n; k++) { if (z[k - 1] != 0.0) { ek *= typeMethods.r8_sign(-z[k - 1]); } if (abd[m + (k - 1) * lda] < Math.Abs(ek - z[k - 1])) { s = abd[m + (k - 1) * lda] / Math.Abs(ek - z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ek = s * ek; } double wk = ek - z[k - 1]; double wkm = -ek - z[k - 1]; s = Math.Abs(wk); double sm = Math.Abs(wkm); wk /= abd[m + (k - 1) * lda]; wkm /= abd[m + (k - 1) * lda]; int j2 = Math.Min(k + m, n); i = m + 1; if (k + 1 <= j2) { for (j = k + 1; j <= j2; j++) { i -= 1; sm += Math.Abs(z[j - 1] + wkm * abd[i - 1 + (j - 1) * lda]); z[j - 1] += wk * abd[i - 1 + (j - 1) * lda]; s += Math.Abs(z[j - 1]); } if (s < sm) { t = wkm - wk; wk = wkm; i = m + 1; for (j = k + 1; j <= j2; j++) { i -= 1; z[j - 1] += t * abd[i - 1 + (j - 1) * lda]; } } } z[k - 1] = wk; } s = BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] /= s; } // // Solve R * Y = W. // for (k = n; 1 <= k; k--) { if (abd[m + (k - 1) * lda] < Math.Abs(z[k - 1])) { s = abd[m + (k - 1) * lda] / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } } z[k - 1] /= abd[m + (k - 1) * lda]; lm = Math.Min(k - 1, m); la = m + 1 - lm; lb = k - lm; t = -z[k - 1]; BLAS1D.daxpy(lm, t, abd, 1, ref z, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lb - 1); } s = BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] /= s; } double ynorm = 1.0; // // Solve R' * V = Y. // for (k = 1; k <= n; k++) { lm = Math.Min(k - 1, m); la = m + 1 - lm; lb = k - lm; z[k - 1] -= BLAS1D.ddot(lm, abd, 1, z, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lb - 1); if (abd[m + (k - 1) * lda] < Math.Abs(z[k - 1])) { s = abd[m + (k - 1) * lda] / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; } z[k - 1] /= abd[m + (k - 1) * lda]; } s = 1.0 / BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; // // Solve R * Z = W. // for (k = n; 1 <= k; k--) { if (abd[m + (k - 1) * lda] < Math.Abs(z[k - 1])) { s = abd[m + (k - 1) * lda] / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; } z[k - 1] /= abd[m + (k - 1) * lda]; lm = Math.Min(k - 1, m); la = m + 1 - lm; lb = k - lm; t = -z[k - 1]; BLAS1D.daxpy(lm, t, abd, 1, ref z, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lb - 1); } // // Make ZNORM = 1.0. // s = 1.0 / BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; if (anorm != 0.0) { rcond = ynorm / anorm; } else { rcond = 0.0; } return(rcond); }