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 dtrdi(ref double[] t, int ldt, int n, ref double[] det, int job) //****************************************************************************80 // // Purpose: // // DTRDI computes the determinant and inverse of a real triangular matrix. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 March 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 T[LDT*N]. // On input, T contains the triangular matrix. The zero elements of the // matrix are not referenced, and the corresponding elements of the array // can be used to store other information. // On output, T contains the inverse matrix, if it was requested. // // Input, int LDT, the leading dimension of T. // // Input, int N, the order of the matrix. // // Output, double DET[2], the determinant of the matrix, if // requested. The determinant = DET[0] * 10.0**DET[1], with // 1.0 <= abs ( DET[0] ) < 10.0, or DET[0] == 0. // // Input, int JOB, specifies the shape of T, and the task. // 010, inverse of lower triangular matrix. // 011, inverse of upper triangular matrix. // 100, determinant only. // 110, determinant and inverse of lower triangular. // 111, determinant and inverse of upper triangular. // // Output, int DTRDI. // If the inverse was requested, then // 0, if the system was nonsingular; // nonzero, if the system was singular. // { int j; int k; double temp; // // Determinant. // int info = 0; if (job / 100 != 0) { det[0] = 1.0; det[1] = 0.0; int i; for (i = 1; i <= n; i++) { det[0] *= t[i - 1 + (i - 1) * ldt]; if (det[0] == 0.0) { break; } 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; } } } switch (job / 10 % 10) { case 0: return(info); } // // Inverse of an upper triangular matrix. // if (job % 10 != 0) { info = 0; for (k = 1; k <= n; k++) { if (t[k - 1 + (k - 1) * ldt] == 0.0) { info = k; break; } t[k - 1 + (k - 1) * ldt] = 1.0 / t[k - 1 + (k - 1) * ldt]; temp = -t[k - 1 + (k - 1) * ldt]; BLAS1D.dscal(k - 1, temp, ref t, 1, index: +0 + (k - 1) * ldt); for (j = k + 1; j <= n; j++) { temp = t[k - 1 + (j - 1) * ldt]; t[k - 1 + (j - 1) * ldt] = 0.0; BLAS1D.daxpy(k, temp, t, 1, ref t, 1, xIndex: +0 + (k - 1) * ldt, yIndex: +0 + (j - 1) * ldt); } } } // // Inverse of a lower triangular matrix. // else { info = 0; for (k = n; 1 <= k; k--) { if (t[k - 1 + (k - 1) * ldt] == 0.0) { info = k; break; } t[k - 1 + (k - 1) * ldt] = 1.0 / t[k - 1 + (k - 1) * ldt]; temp = -t[k - 1 + (k - 1) * ldt]; if (k != n) { BLAS1D.dscal(n - k, temp, ref t, 1, index: +k + (k - 1) * ldt); } for (j = 1; j <= k - 1; j++) { temp = t[k - 1 + (j - 1) * ldt]; t[k - 1 + (j - 1) * ldt] = 0.0; BLAS1D.daxpy(n - k + 1, temp, t, 1, ref t, 1, xIndex: +k - 1 + (k - 1) * ldt, yIndex: +k - 1 + (j - 1) * ldt); } } } 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 int dgefa(ref double[] a, int lda, int n, ref int[] ipvt) //****************************************************************************80 // // Purpose: // // DGEFA factors a real general matrix. // // 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/output, double A[LDA*N]. // On intput, the matrix to be factored. // On output, an upper triangular matrix and the multipliers 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 A. // // Input, int N, the order of the matrix A. // // Output, int IPVT[N], the pivot indices. // // Output, int DGEFA, singularity indicator. // 0, normal value. // K, if U(K,K) == 0. This is not an error condition for this subroutine, // but it does indicate that DGESL or DGEDI will divide by zero if called. // Use RCOND in DGECO for a reliable indication of singularity. // { int k; // // Gaussian elimination with partial pivoting. // int info = 0; for (k = 1; k <= n - 1; k++) { // // Find L = pivot index. // int l = BLAS1D.idamax(n - k + 1, a, 1, index: +(k - 1) + (k - 1) * lda) + k - 1; ipvt[k - 1] = l; switch (a[l - 1 + (k - 1) * lda]) { // // Zero pivot implies this column already triangularized. // case 0.0: info = k; continue; } // // Interchange if necessary. // double t; if (l != k) { t = a[l - 1 + (k - 1) * lda]; a[l - 1 + (k - 1) * lda] = a[k - 1 + (k - 1) * lda]; a[k - 1 + (k - 1) * lda] = t; } // // Compute multipliers. // t = -1.0 / a[k - 1 + (k - 1) * lda]; BLAS1D.dscal(n - k, t, ref a, 1, index: +k + (k - 1) * lda); // // Row elimination with column indexing. // int j; for (j = k + 1; j <= n; j++) { t = a[l - 1 + (j - 1) * lda]; if (l != k) { a[l - 1 + (j - 1) * lda] = a[k - 1 + (j - 1) * lda]; a[k - 1 + (j - 1) * lda] = t; } BLAS1D.daxpy(n - k, t, a, 1, ref a, 1, xIndex: +k + (k - 1) * lda, yIndex: +k + (j - 1) * lda); } } ipvt[n - 1] = n; info = a[n - 1 + (n - 1) * lda] switch { 0.0 => n, _ => info }; return(info); } }
public static int dsifa(ref double[] a, int lda, int n, ref int[] kpvt) //****************************************************************************80 // // Purpose: // // DSIFA factors a real symmetric matrix. // // Discussion: // // To solve A*X = B, follow DSIFA by DSISL. // // To compute inverse(A)*C, follow DSIFA by DSISL. // // To compute determinant(A), follow DSIFA by DSIDI. // // To compute inertia(A), follow DSIFA by DSIDI. // // To compute inverse(A), follow DSIFA by DSIDI. // // 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 symmetric matrix // to be factored. Only the diagonal and upper triangle are used. // On output, a block diagonal matrix and the multipliers which // were used to obtain it. The factorization can be written A = U*D*U' // where U is a product of permutation and unit upper triangular // matrices, U' is the transpose of U, and D is block diagonal // with 1 by 1 and 2 by 2 blocks. // // Input, int LDA, the leading dimension of the array A. // // Input, int N, the order of the matrix. // // Output, int KPVT[N], the pivot indices. // // Output, integer DSIFA, error flag. // 0, normal value. // K, if the K-th pivot block is singular. This is not an error // condition for this subroutine, but it does indicate that DSISL // or DSIDI may divide by zero if called. // { // // ALPHA is used in choosing pivot block size. // double alpha = (1.0 + Math.Sqrt(17.0)) / 8.0; int info = 0; // // Main loop on K, which goes from N to 1. // int k = n; while (0 < k) { switch (k) { case 1: { kpvt[0] = 1; info = a[0 + 0 * lda] switch { 0.0 => 1, _ => info }; return(info); } } // // This section of code determines the kind of // elimination to be performed. When it is completed, // KSTEP will be set to the size of the pivot block, and // SWAP will be set to .true. if an interchange is required. // double absakk = Math.Abs(a[k - 1 + (k - 1) * lda]); // // Determine the largest off-diagonal element in column K. // int imax = BLAS1D.idamax(k - 1, a, 1, index: +0 + (k - 1) * lda); double colmax = Math.Abs(a[imax - 1 + (k - 1) * lda]); int j; int kstep; bool swap; if (alpha * colmax <= absakk) { kstep = 1; swap = false; } // // Determine the largest off-diagonal element in row IMAX. // else { double rowmax = 0.0; int imaxp1 = imax + 1; for (j = imaxp1; j <= k; j++) { rowmax = Math.Max(rowmax, Math.Abs(a[imax - 1 + (j - 1) * lda])); } if (imax != 1) { int jmax = BLAS1D.idamax(imax - 1, a, 1, index: +0 + (imax - 1) * lda); rowmax = Math.Max(rowmax, Math.Abs(a[jmax - 1 + (imax - 1) * lda])); } if (alpha * rowmax <= Math.Abs(a[imax - 1 + (imax - 1) * lda])) { kstep = 1; swap = true; } else if (alpha * colmax * (colmax / rowmax) <= absakk) { kstep = 1; swap = false; } else { kstep = 2; swap = imax != k - 1; } } switch (Math.Max(absakk, colmax)) { // // Column K is zero. // Set INFO and iterate the loop. // case 0.0: kpvt[k - 1] = k; info = k; break; // default: { int jj; double mulk; double t; if (kstep != 2) { switch (swap) { case true: { BLAS1D.dswap(imax, ref a, 1, ref a, 1, xIndex: +0 + (imax - 1) * lda, yIndex: +0 + (k - 1) * lda); for (jj = imax; jj <= k; jj++) { j = k + imax - jj; t = a[j - 1 + (k - 1) * lda]; a[j - 1 + (k - 1) * lda] = a[imax - 1 + (j - 1) * lda]; a[imax - 1 + (j - 1) * lda] = t; } break; } } // // Perform the elimination. // for (jj = 1; jj <= k - 1; jj++) { j = k - jj; mulk = -a[j - 1 + (k - 1) * lda] / a[k - 1 + (k - 1) * lda]; t = mulk; BLAS1D.daxpy(j, t, a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (j - 1) * lda); a[j - 1 + (k - 1) * lda] = mulk; } kpvt[k - 1] = swap switch { // // Set the pivot array. // true => imax, _ => k }; } // // 2 x 2 pivot block. // // Perform an interchange. // else { switch (swap) { case true: { BLAS1D.dswap(imax, ref a, 1, ref a, 1, xIndex: +0 + (imax - 1) * lda, yIndex: +0 + (k - 2) * lda); for (jj = imax; jj <= k - 1; jj++) { j = k - 1 + imax - jj; t = a[j - 1 + (k - 1) * lda]; a[j - 1 + (k - 1) * lda] = a[imax - 1 + (j - 1) * lda]; a[imax - 1 + (j - 1) * lda] = t; } t = a[k - 2 + (k - 1) * lda]; a[k - 2 + (k - 1) * lda] = a[imax - 1 + (k - 1) * lda]; a[imax - 1 + (k - 1) * lda] = t; break; } } // // Perform the elimination. // if (k - 2 != 0) { double ak = a[k - 1 + (k - 1) * lda] / a[k - 2 + (k - 1) * lda]; double akm1 = a[k - 2 + (k - 2) * lda] / a[k - 2 + (k - 1) * lda]; double denom = 1.0 - ak * akm1; for (jj = 1; jj <= k - 2; jj++) { j = k - 1 - jj; double bk = a[j - 1 + (k - 1) * lda] / a[k - 2 + (k - 1) * lda]; double bkm1 = a[j - 1 + (k - 2) * lda] / a[k - 2 + (k - 1) * lda]; mulk = (akm1 * bk - bkm1) / denom; double mulkm1 = (ak * bkm1 - bk) / denom; t = mulk; BLAS1D.daxpy(j, t, a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (j - 1) * lda); t = mulkm1; BLAS1D.daxpy(j, t, a, 1, ref a, 1, xIndex: +0 + (k - 2) * lda, yIndex: +0 + (j - 1) * lda); a[j - 1 + (k - 1) * lda] = mulk; a[j - 1 + (k - 2) * lda] = mulkm1; } } kpvt[k - 1] = swap switch { // // Set the pivot array. // true => - imax, _ => 1 - k }; kpvt[k - 2] = kpvt[k - 1]; } break; } } k -= kstep; } return(info); } }
public static void dppdi(ref double[] ap, int n, ref double[] det, int job) //****************************************************************************80 // // Purpose: // // DPPDI computes the determinant and inverse of a matrix factored by DPPCO or DPPFA. // // Discussion: // // A division by zero will occur if the input factor contains // a zero on the diagonal and the inverse is requested. // It will not occur if the subroutines are called correctly // and if DPOCO or DPOFA has set INFO == 0. // // 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 output from // DPPCO or DPPFA. On output, the upper triangular half of the // inverse, if requested. // // Input, int N, the order of the matrix. // // Output, double DET[2], the determinant of the original matrix // if requested. // determinant = DET[0] * 10.0**DET[1] // with 1.0D+00 <= DET[0] < 10.0D+00 or DET[0] == 0.0D+00. // // Input, int JOB, job request. // 11, both determinant and inverse. // 01, inverse only. // 10, determinant only. // { // // Compute the determinant. // if (job / 10 != 0) { det[0] = 1.0; det[1] = 0.0; const double s = 10.0; int ii = 0; int i; for (i = 1; i <= n; i++) { ii += i; det[0] = det[0] * ap[ii - 1] * ap[ii - 1]; if (det[0] == 0.0) { break; } while (det[0] < 1.0) { det[0] *= s; det[1] -= 1.0; } while (s <= det[0]) { det[0] /= s; det[1] += 1.0; } } } // // Compute inverse(R). // if (job % 10 == 0) { return; } int kk = 0; int k; int k1; int kj; int j1; double t; int j; for (k = 1; k <= n; k++) { k1 = kk + 1; kk += k; ap[kk - 1] = 1.0 / ap[kk - 1]; t = -ap[kk - 1]; BLAS1D.dscal(k - 1, t, ref ap, 1, index: +k1 - 1); j1 = kk + 1; kj = kk + k; for (j = k + 1; j <= n; j++) { t = ap[kj - 1]; ap[kj - 1] = 0.0; BLAS1D.daxpy(k, t, ap, 1, ref ap, 1, xIndex: +k1 - 1, yIndex: +j1 - 1); j1 += j; kj += j; } } // // Form inverse(R) * (inverse(R))'. // int jj = 0; for (j = 1; j <= n; j++) { j1 = jj + 1; jj += j; k1 = 1; kj = j1; for (k = 1; k <= j - 1; k++) { t = ap[kj - 1]; BLAS1D.daxpy(k, t, ap, 1, ref ap, 1, xIndex: +j1 - 1, yIndex: +k1 - 1); k1 += k; kj += 1; } t = ap[jj - 1]; BLAS1D.dscal(j, t, ref ap, 1, index: +j1 - 1); } }
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 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 int dchdc(ref double[] a, int lda, int p, double[] work, ref int[] ipvt, int job) //****************************************************************************80 // // Purpose: // // DCHDC computes the Cholesky decomposition of a positive definite matrix. // // Discussion: // // A pivoting option allows the user to estimate the condition of a // positive definite matrix or determine the rank of a positive // semidefinite matrix. // // For positive definite matrices, INFO = P is the normal return. // // For pivoting with positive semidefinite matrices, INFO will // in general be less than P. However, INFO may be greater than // the rank of A, since rounding error can cause an otherwise zero // element to be positive. Indefinite systems will always cause // INFO to be less than P. // // 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 A[LDA*P]. // On input, A contains the matrix whose decomposition is to // be computed. Only the upper half of A need be stored. // The lower part of the array a is not referenced. // On output, A contains in its upper half the Cholesky factor // of the input matrix, as it has been permuted by pivoting. // // Input, int LDA, the leading dimension of the array A. // // Input, int P, the order of the matrix. // // Input, double WORK[P] is a work array. // // Input/output, int IPVT[P]. // On input, IPVT contains integers that control the selection // of the pivot elements, if pivoting has been requested. // Each diagonal element A(K,K) is placed in one of three classes // according to the value of IPVT(K). // // > 0, then X(K) is an initial element. // = 0, then X(K) is a free element. // < 0, then X(K) is a final element. // // Before the decomposition is computed, initial elements are moved by // symmetric row and column interchanges to the beginning of the array A // and final elements to the end. Both initial and final elements are // frozen in place during the computation and only free elements are moved. // At the K-th stage of the reduction, if A(K,K) is occupied by a free // element, it is interchanged with the largest free element A(L,L) with // K <= L. IPVT is not referenced if JOB is 0. // // On output, IPVT(J) contains the index of the diagonal element // of A that was moved into the J-th position, if pivoting was requested. // // Input, int JOB, initiates column pivoting. // 0, no pivoting is done. // nonzero, pivoting is done. // // Output, int DCHDC, contains the index of the last positive diagonal // element of the Cholesky factor. // { int j; int k; double temp; int pl = 1; int pu = 0; int info = p; // // Pivoting has been requested. // Rearrange the the elements according to IPVT. // if (job != 0) { for (k = 1; k <= p; k++) { bool swapk = 0 < ipvt[k - 1]; bool negk = ipvt[k - 1] < 0; ipvt[k - 1] = negk switch { true => - k, _ => k }; switch (swapk) { case true: { if (k != pl) { BLAS1D.dswap(pl - 1, ref a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (pl - 1) * lda); temp = a[k - 1 + (k - 1) * lda]; a[k - 1 + (k - 1) * lda] = a[pl - 1 + (pl - 1) * lda]; a[pl - 1 + (pl - 1) * lda] = temp; for (j = pl + 1; j <= p; j++) { if (j < k) { temp = a[pl - 1 + (j - 1) * lda]; a[pl - 1 + (j - 1) * lda] = a[j - 1 + (k - 1) * lda]; a[j - 1 + (k - 1) * lda] = temp; } else if (k < j) { temp = a[k - 1 + (j - 1) * lda]; a[k - 1 + (j - 1) * lda] = a[pl - 1 + (j - 1) * lda]; a[pl - 1 + (j - 1) * lda] = temp; } } ipvt[k - 1] = ipvt[pl - 1]; ipvt[pl - 1] = k; } pl += 1; break; } } } pu = p; for (k = p; pl <= k; k--) { switch (ipvt[k - 1]) { case < 0: { ipvt[k - 1] = -ipvt[k - 1]; if (pu != k) { BLAS1D.dswap(k - 1, ref a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (pu - 1) * lda); temp = a[k - 1 + (k - 1) * lda]; a[k - 1 + (k - 1) * lda] = a[pu - 1 + (pu - 1) * lda]; a[pu - 1 + (pu - 1) * lda] = temp; for (j = k + 1; j <= p; j++) { if (j < pu) { temp = a[k - 1 + (j - 1) * lda]; a[k - 1 + (j - 1) * lda] = a[j - 1 + (pu - 1) * lda]; a[j - 1 + (pu - 1) * lda] = temp; } else if (pu < j) { temp = a[k - 1 + (j - 1) * lda]; a[k - 1 + (j - 1) * lda] = a[pu - 1 + (j - 1) * lda]; a[pu - 1 + (j - 1) * lda] = temp; } } (ipvt[k - 1], ipvt[pu - 1]) = (ipvt[pu - 1], ipvt[k - 1]); } pu -= 1; break; } } } } for (k = 1; k <= p; k++) { // // Reduction loop. // double maxdia = a[k - 1 + (k - 1) * lda]; int maxl = k; // // Determine the pivot element. // if (pl <= k && k < pu) { int l; for (l = k + 1; l <= pu; l++) { if (!(maxdia < a[l - 1 + (l - 1) * lda])) { continue; } maxdia = a[l - 1 + (l - 1) * lda]; maxl = l; } } switch (maxdia) { // // Quit if the pivot element is not positive. // case <= 0.0: info = k - 1; return(info); } // // Start the pivoting and update IPVT. // if (k != maxl) { BLAS1D.dswap(k - 1, ref a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (maxl - 1) * lda); a[maxl - 1 + (maxl - 1) * lda] = a[k - 1 + (k - 1) * lda]; a[k - 1 + (k - 1) * lda] = maxdia; (ipvt[maxl - 1], ipvt[k - 1]) = (ipvt[k - 1], ipvt[maxl - 1]); } // // Reduction step. // Pivoting is contained across the rows. // work[k - 1] = Math.Sqrt(a[k - 1 + (k - 1) * lda]); a[k - 1 + (k - 1) * lda] = work[k - 1]; for (j = k + 1; j <= p; j++) { if (k != maxl) { if (j < maxl) { temp = a[k - 1 + (j - 1) * lda]; a[k - 1 + (j - 1) * lda] = a[j - 1 + (maxl - 1) * lda]; a[j - 1 + (maxl - 1) * lda] = temp; } else if (maxl < j) { temp = a[k - 1 + (j - 1) * lda]; a[k - 1 + (j - 1) * lda] = a[maxl - 1 + (j - 1) * lda]; a[maxl - 1 + (j - 1) * lda] = temp; } } a[k - 1 + (j - 1) * lda] /= work[k - 1]; work[j - 1] = a[k - 1 + (j - 1) * lda]; temp = -a[k - 1 + (j - 1) * lda]; BLAS1D.daxpy(j - k, temp, work, 1, ref a, 1, xIndex: +k, yIndex: +k + (j - 1) * lda); } } return(info); } }
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 dgedi(ref double[] a, int lda, int n, int[] ipvt, ref double[] det, double[] work, int job) //****************************************************************************80 // // Purpose: // // DGEDI computes the determinant and inverse of a matrix factored by DGECO or DGEFA. // // Discussion: // // A division by zero will occur if the input factor contains // a zero on the diagonal and the inverse is requested. // 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: // // 17 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 LU factor information, // as output by DGECO or DGEFA. On output, the inverse // matrix if requested. // // Input, int LDA, the leading dimension of the array A. // // Input, int N, the order of the matrix A. // // Input, int IPVT[N], the pivot vector from DGECO or DGEFA. // // Workspace, double WORK[N]. // // Output, double DET[2], the determinant of original matrix if // requested. The determinant = DET[0] * pow ( 10.0, DET[1] ) // with 1.0 <= abs ( DET[0] ) < 10.0 or DET[0] == 0.0. // // Input, int JOB, specifies what is to be computed. // 11, both determinant and inverse. // 01, inverse only. // 10, determinant only. // { int i; // // Compute the determinant. // if (job / 10 != 0) { det[0] = 1.0; det[1] = 0.0; for (i = 1; i <= n; i++) { if (ipvt[i - 1] != i) { det[0] = -det[0]; } det[0] *= a[i - 1 + (i - 1) * lda]; if (det[0] == 0.0) { break; } 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; } } } // // Compute inverse(U). // if (job % 10 == 0) { return; } int j; double t; int k; for (k = 1; k <= n; k++) { a[k - 1 + (k - 1) * lda] = 1.0 / a[k - 1 + (k - 1) * lda]; t = -a[k - 1 + (k - 1) * lda]; BLAS1D.dscal(k - 1, t, ref a, 1, index: +0 + (k - 1) * lda); for (j = k + 1; j <= n; j++) { t = a[k - 1 + (j - 1) * lda]; a[k - 1 + (j - 1) * lda] = 0.0; BLAS1D.daxpy(k, t, a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (j - 1) * lda); } } // // Form inverse(U) * inverse(L). // for (k = n - 1; 1 <= k; k--) { for (i = k + 1; i <= n; i++) { work[i - 1] = a[i - 1 + (k - 1) * lda]; a[i - 1 + (k - 1) * lda] = 0.0; } for (j = k + 1; j <= n; j++) { t = work[j - 1]; BLAS1D.daxpy(n, t, a, 1, ref a, 1, xIndex: +0 + (j - 1) * lda, yIndex: +0 + (k - 1) * lda); } int l = ipvt[k - 1]; if (l != k) { BLAS1D.dswap(n, ref a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (l - 1) * lda); } } }
public static void dpodi(ref double[] a, int lda, int n, ref double[] det, int job) //****************************************************************************80 // // Purpose: // // DPODI computes the determinant and inverse of a certain matrix. // // Discussion: // // The matrix is real symmetric positive definite. // DPODI uses the factors computed by DPOCO, DPOFA or DQRDC. // // A division by zero will occur if the input factor contains // a zero on the diagonal and the inverse is requested. // It will not occur if the subroutines are called correctly // and if DPOCO or DPOFA has set 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/output, double A[LDA*N]. On input, the output A from // DPOCO or DPOFA, or the output X from DQRDC. On output, if DPOCO or // DPOFA was used to factor A then DPODI produces the upper half of // inverse(A). If DQRDC was used to decompose X then DPODI produces // the upper half of inverse(X'*X) where X' is the transpose. // Elements of A below the diagonal are unchanged. If the units digit // of JOB is zero, A is unchanged. // // Input, int LDA, the leading dimension of the array A. // // Input, int N, the order of the matrix A. // // Input, int JOB, specifies the task. // 11, both determinant and inverse. // 01, inverse only. // 10, determinant only. // // Output, double DET[2], the determinant of A or of X'*X // if requested. // determinant = DET[0] * 10.0**DET[1] // with 1.0D+00 <= DET[0] < 10.0D+00 or DET[0] == 0.0D+00. // { // // Compute the determinant. // if (job / 10 != 0) { det[0] = 1.0; det[1] = 0.0; const double s = 10.0; int i; for (i = 1; i <= n; i++) { det[0] = det[0] * a[i - 1 + (i - 1) * lda] * a[i - 1 + (i - 1) * lda]; if (det[0] == 0.0) { break; } while (det[0] < 1.0) { det[0] *= s; det[1] -= 1.0; } while (s <= det[0]) { det[0] /= s; det[1] += 1.0; } } } // // Compute inverse(R). // if (job % 10 == 0) { return; } double t; int k; int j; for (k = 1; k <= n; k++) { a[k - 1 + (k - 1) * lda] = 1.0 / a[k - 1 + (k - 1) * lda]; t = -a[k - 1 + (k - 1) * lda]; BLAS1D.dscal(k - 1, t, ref a, 1, index: +0 + (k - 1) * lda); for (j = k + 1; j <= n; j++) { t = a[k - 1 + (j - 1) * lda]; a[k - 1 + (j - 1) * lda] = 0.0; BLAS1D.daxpy(k, t, a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (j - 1) * lda); } } // // Form inverse(R) * (inverse(R))'. // for (j = 1; j <= n; j++) { for (k = 1; k <= j - 1; k++) { t = a[k - 1 + (j - 1) * lda]; BLAS1D.daxpy(k, t, a, 1, ref a, 1, xIndex: +0 + (j - 1) * lda, yIndex: +0 + (k - 1) * lda); } t = a[j - 1 + (j - 1) * lda]; BLAS1D.dscal(j, t, ref a, 1, index: +0 + (j - 1) * lda); } }
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 double dtrco(double[] t, int ldt, int n, ref double[] z, int job) //****************************************************************************80 // // Purpose: // // DTRCO estimates the condition of a real triangular matrix. // // 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 T[LDT*N], the triangular matrix. 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. // // Output, double Z[N] a work vector whose contents are usually // unimportant. If T 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). // // Input, int JOB, indicates the shape of T: // 0, T is lower triangular. // nonzero, T is upper triangular. // // Output, double DTRCO, an estimate of the reciprocal condition RCOND // of T. For the system T*X = B, relative perturbations in T 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 T may be singular to working precision. In particular, // RCOND is zero if exact singularity is detected or the estimate underflows. // { int i; int i1; int j; int k; int kk; double rcond; double s; double w; bool lower = job == 0; // // Compute the 1-norm of T. // double tnorm = 0.0; for (j = 1; j <= n; j++) { int l; switch (lower) { case true: l = n + 1 - j; i1 = j; break; default: l = j; i1 = 1; break; } tnorm = Math.Max(tnorm, BLAS1D.dasum(l, t, 1, index: +i1 - 1 + (j - 1) * ldt)); } // // RCOND = 1/(norm(T)*(estimate of norm(inverse(T)))). // // Estimate = norm(Z)/norm(Y) where T * Z = Y and T' * Y = E. // // T' is the transpose of T. // // The components of E are chosen to cause maximum local // growth in the elements of Y. // // The vectors are frequently rescaled to avoid overflow. // // Solve T' * Y = E. // double ek = 1.0; for (i = 1; i <= n; i++) { z[i - 1] = 0.0; } for (kk = 1; kk <= n; kk++) { k = lower switch { true => n + 1 - kk, _ => kk }; if (z[k - 1] != 0.0) { ek = typeMethods.r8_sign(-z[k - 1]) * ek; } if (Math.Abs(t[k - 1 + (k - 1) * ldt]) < Math.Abs(ek - z[k - 1])) { s = Math.Abs(t[k - 1 + (k - 1) * ldt]) / 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 (t[k - 1 + (k - 1) * ldt] != 0.0) { wk /= t[k - 1 + (k - 1) * ldt]; wkm /= t[k - 1 + (k - 1) * ldt]; } else { wk = 1.0; wkm = 1.0; } if (kk != n) { int j2; int j1; switch (lower) { case true: j1 = 1; j2 = k - 1; break; default: j1 = k + 1; j2 = n; break; } for (j = j1; j <= j2; j++) { sm += Math.Abs(z[j - 1] + wkm * t[k - 1 + (j - 1) * ldt]); z[j - 1] += wk * t[k - 1 + (j - 1) * ldt]; s += Math.Abs(z[j - 1]); } if (s < sm) { w = wkm - wk; wk = wkm; for (j = j1; j <= j2; j++) { z[j - 1] += w * t[k - 1 + (j - 1) * ldt]; } } } z[k - 1] = wk; } double temp = BLAS1D.dasum(n, z, 1); for (i = 1; i <= n; i++) { z[i - 1] /= temp; } double ynorm = 1.0; // // Solve T * Z = Y. // for (kk = 1; kk <= n; kk++) { k = lower switch { true => kk, _ => n + 1 - kk }; if (Math.Abs(t[k - 1 + (k - 1) * ldt]) < Math.Abs(z[k - 1])) { s = Math.Abs(t[k - 1 + (k - 1) * ldt]) / Math.Abs(z[k - 1]); for (i = 1; i <= n; i++) { z[i - 1] = s * z[i - 1]; } ynorm = s * ynorm; } if (t[k - 1 + (k - 1) * ldt] != 0.0) { z[k - 1] /= t[k - 1 + (k - 1) * ldt]; } else { z[k - 1] = 1.0; } i1 = lower switch { true => k + 1, _ => 1 }; if (kk >= n) { continue; } w = -z[k - 1]; BLAS1D.daxpy(n - kk, w, t, 1, ref z, 1, xIndex: +i1 - 1 + (k - 1) * ldt, yIndex: +i1 - 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 (tnorm != 0.0) { rcond = ynorm / tnorm; } else { rcond = 0.0; } return(rcond); } }
public static int dspfa(ref double[] ap, int n, ref int[] kpvt) //****************************************************************************80 // // Purpose: // // DSPFA factors a real symmetric matrix stored in packed form. // // Discussion: // // To solve A*X = B, follow DSPFA by DSPSL. // // To compute inverse(A)*C, follow DSPFA by DSPSL. // // To compute determinant(A), follow DSPFA by DSPDI. // // To compute inertia(A), follow DSPFA by DSPDI. // // To compute inverse(A), follow DSPFA by DSPDI. // // 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: // // 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 packed form of a // symmetric matrix A. The columns of the upper triangle are stored // sequentially in a one-dimensional array. On output, a block diagonal // matrix and the multipliers which were used to obtain it stored in // packed form. The factorization can be written A = U*D*U' where U // is a product of permutation and unit upper triangular matrices, U' // is the transpose of U, and D is block diagonal with 1 by 1 and 2 // by 2 blocks. // // Input, int N, the order of the matrix. // // Output, int KPVT[N], the pivot indices. // // Output, int DSPFA, error flag. // 0, normal value. // K, if the K-th pivot block is singular. This is not an error // condition for this subroutine, but it does indicate that DSPSL or // DSPDI may divide by zero if called. // { int im = 0; // // ALPHA is used in choosing pivot block size. // double alpha = (1.0 + Math.Sqrt(17.0)) / 8.0; int info = 0; // // Main loop on K, which goes from N to 1. // int k = n; int ik = n * (n - 1) / 2; for (;;) { // // Leave the loop if K = 0 or K = 1. // if (k == 0) { break; } if (k == 1) { kpvt[0] = 1; info = ap[0] switch { 0.0 => 1, _ => info }; break; } // // This section of code determines the kind of elimination to be performed. // When it is completed, KSTEP will be set to the size of the pivot block, // and SWAP will be set to .true. if an interchange is required. // int km1 = k - 1; int kk = ik + k; double absakk = Math.Abs(ap[kk - 1]); // // Determine the largest off-diagonal element in column K. // int imax = BLAS1D.idamax(k - 1, ap, 1, index: +ik); int imk = ik + imax; double colmax = Math.Abs(ap[imk - 1]); int kstep; bool swap; int j; int imj; if (alpha * colmax <= absakk) { kstep = 1; swap = false; } // // Determine the largest off-diagonal element in row IMAX. // else { double rowmax = 0.0; int imaxp1 = imax + 1; im = imax * (imax - 1) / 2; imj = im + 2 * imax; for (j = imaxp1; j <= k; j++) { rowmax = Math.Max(rowmax, Math.Abs(ap[imj - 1])); imj += j; } if (imax != 1) { int jmax = BLAS1D.idamax(imax - 1, ap, 1, index: +im); int jmim = jmax + im; rowmax = Math.Max(rowmax, Math.Abs(ap[jmim - 1])); } int imim = imax + im; if (alpha * rowmax <= Math.Abs(ap[imim - 1])) { kstep = 1; swap = true; } else if (alpha * colmax * (colmax / rowmax) <= absakk) { kstep = 1; swap = false; } else { kstep = 2; swap = imax != km1; } } switch (Math.Max(absakk, colmax)) { // // Column K is zero. Set INFO and iterate the loop. // case 0.0: kpvt[k - 1] = k; info = k; break; default: { double mulk; int jk; int jj; double t; int ij; if (kstep != 2) { switch (swap) { // // 1 x 1 pivot block. // case true: { // // Perform an interchange. // BLAS1D.dswap(imax, ref ap, 1, ref ap, 1, xIndex: +im, yIndex: +ik); imj = ik + imax; for (jj = imax; jj <= k; jj++) { j = k + imax - jj; jk = ik + j; t = ap[jk - 1]; ap[jk - 1] = ap[imj - 1]; ap[imj - 1] = t; imj -= j - 1; } break; } } // // Perform the elimination. // ij = ik - (k - 1); for (jj = 1; jj <= km1; jj++) { j = k - jj; jk = ik + j; mulk = -ap[jk - 1] / ap[kk - 1]; t = mulk; BLAS1D.daxpy(j, t, ap, 1, ref ap, 1, xIndex: +ik, yIndex: +ij); ap[jk - 1] = mulk; ij -= j - 1; } kpvt[k - 1] = swap switch { // // Set the pivot array. // true => imax, _ => k }; } else { // // 2 x 2 pivot block. // int km1k = ik + k - 1; int ikm1 = ik - (k - 1); int jkm1; switch (swap) { // // Perform an interchange. // case true: { BLAS1D.dswap(imax, ref ap, 1, ref ap, 1, xIndex: +im, yIndex: +ikm1); imj = ikm1 + imax; for (jj = imax; jj <= km1; jj++) { j = km1 + imax - jj; jkm1 = ikm1 + j; t = ap[jkm1 - 1]; ap[jkm1 - 1] = ap[imj - 1]; ap[imj - 1] = t; imj -= j - 1; } t = ap[km1k - 1]; ap[km1k - 1] = ap[imk - 1]; ap[imk - 1] = t; break; } } // // Perform the elimination. // if (k - 2 != 0) { double ak = ap[kk - 1] / ap[km1k - 1]; int km1km1 = ikm1 + k - 1; double akm1 = ap[km1km1 - 1] / ap[km1k - 1]; double denom = 1.0 - ak * akm1; ij = ik - (k - 1) - (k - 2); for (jj = 1; jj <= k - 2; jj++) { j = km1 - jj; jk = ik + j; double bk = ap[jk - 1] / ap[km1k - 1]; jkm1 = ikm1 + j; double bkm1 = ap[jkm1 - 1] / ap[km1k - 1]; mulk = (akm1 * bk - bkm1) / denom; double mulkm1 = (ak * bkm1 - bk) / denom; t = mulk; BLAS1D.daxpy(j, t, ap, 1, ref ap, 1, xIndex: +ik, yIndex: +ij); t = mulkm1; BLAS1D.daxpy(j, t, ap, 1, ref ap, 1, xIndex: +ikm1, yIndex: +ij); ap[jk - 1] = mulk; ap[jkm1 - 1] = mulkm1; ij -= j - 1; } } kpvt[k - 1] = swap switch { // // Set the pivot array. // true => - imax, _ => 1 - k }; kpvt[k - 2] = kpvt[k - 1]; } break; } } ik -= k - 1; switch (kstep) { case 2: ik -= k - 2; break; } k -= kstep; } return(info); } }
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 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 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 int dgbfa(ref double[] abd, int lda, int n, int ml, int mu, ref int[] ipvt) //****************************************************************************80 // // Purpose: // // DGBFA factors a real band matrix by elimination. // // Discussion: // // DGBFA is usually called by DGBCO, but it can be called // directly with a saving in time if RCOND is not needed. // // 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 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. // // Output, integer DGBFA, error flag. // 0, normal value. // K, if U(K,K) == 0.0D+00. This is not an error condition for this // subroutine, but it does indicate that DGBSL will divide by zero if // called. Use RCOND in DGBCO for a reliable indication of singularity. // { int i; int jz; int k; int m = ml + mu + 1; int info = 0; // // Zero initial fill-in columns. // int j0 = mu + 2; int j1 = Math.Min(n, m) - 1; for (jz = j0; jz <= j1; jz++) { int i0 = m + 1 - jz; for (i = i0; i <= ml; i++) { abd[i - 1 + (jz - 1) * lda] = 0.0; } } jz = j1; int ju = 0; // // Gaussian elimination with partial pivoting. // for (k = 1; k <= n - 1; k++) { // // Zero out the next fill-in column. // jz += 1; if (jz <= n) { for (i = 1; i <= ml; i++) { abd[i - 1 + (jz - 1) * lda] = 0.0; } } // // Find L = pivot index. // int lm = Math.Min(ml, n - k); int l = BLAS1D.idamax(lm + 1, abd, 1, +m - 1 + (k - 1) * lda) + m - 1; ipvt[k - 1] = l + k - m; switch (abd[l - 1 + (k - 1) * lda]) { // // Zero pivot implies this column already triangularized. // case 0.0: info = k; break; // default: { double t; if (l != m) { t = abd[l - 1 + (k - 1) * lda]; abd[l - 1 + (k - 1) * lda] = abd[m - 1 + (k - 1) * lda]; abd[m - 1 + (k - 1) * lda] = t; } // // Compute multipliers. // t = -1.0 / abd[m - 1 + (k - 1) * lda]; BLAS1D.dscal(lm, t, ref abd, 1, +m + (k - 1) * lda); // // Row elimination with column indexing. // ju = Math.Min(Math.Max(ju, mu + ipvt[k - 1]), n); int mm = m; int j; for (j = k + 1; j <= ju; j++) { l -= 1; mm -= 1; t = abd[l - 1 + (j - 1) * lda]; if (l != mm) { abd[l - 1 + (j - 1) * lda] = abd[mm - 1 + (j - 1) * lda]; abd[mm - 1 + (j - 1) * lda] = t; } BLAS1D.daxpy(lm, t, abd, 1, ref abd, 1, +m + (k - 1) * lda, +mm + (j - 1) * lda); } break; } } } ipvt[n - 1] = n; info = abd[m - 1 + (n - 1) * lda] switch { 0.0 => n, _ => info }; return(info); } }
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 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); }
private static void daxpy_test() //****************************************************************************80 // // Purpose: // // DAXPY_TEST tests DAXPY. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 15 May 2006 // // Author: // // John Burkardt // { const int N = 6; double[] x = new double[N]; double[] y = new double[N]; for (int i = 0; i < N; i++) { x[i] = i + 1; } for (int i = 0; i < N; i++) { y[i] = 100 * (i + 1); } Console.WriteLine(""); Console.WriteLine("DAXPY_TEST"); Console.WriteLine(" DAXPY adds a multiple of vector X to vector Y."); Console.WriteLine(""); Console.WriteLine(" X ="); Console.WriteLine(""); for (int i = 0; i < N; i++) { Console.WriteLine(" " + (i + 1).ToString(CultureInfo.InvariantCulture).PadLeft(6) + " " + x[i].ToString(CultureInfo.InvariantCulture).PadLeft(14) + ""); } Console.WriteLine(""); Console.WriteLine(" Y ="); Console.WriteLine(""); for (int i = 0; i < N; i++) { Console.WriteLine(" " + (i + 1).ToString(CultureInfo.InvariantCulture).PadLeft(6) + " " + y[i].ToString(CultureInfo.InvariantCulture).PadLeft(14) + ""); } double da = 1.0; BLAS1D.daxpy(N, da, x, 1, ref y, 1); Console.WriteLine(""); Console.WriteLine(" DAXPY ( N, " + da + ", X, 1, Y, 1 )"); Console.WriteLine(""); Console.WriteLine(" Y ="); Console.WriteLine(""); for (int i = 0; i < N; i++) { Console.WriteLine(" " + (i + 1).ToString(CultureInfo.InvariantCulture).PadLeft(6) + " " + y[i].ToString(CultureInfo.InvariantCulture).PadLeft(14) + ""); } for (int i = 0; i < N; i++) { y[i] = 100 * (i + 1); } da = -2.0; BLAS1D.daxpy(N, da, x, 1, ref y, 1); Console.WriteLine(""); Console.WriteLine(" DAXPY ( N, " + da + ", X, 1, Y, 1 )"); Console.WriteLine(""); Console.WriteLine(" Y ="); Console.WriteLine(""); for (int i = 0; i < N; i++) { Console.WriteLine(" " + (i + 1).ToString(CultureInfo.InvariantCulture).PadLeft(6) + " " + y[i].ToString(CultureInfo.InvariantCulture).PadLeft(14) + ""); } for (int i = 0; i < N; i++) { y[i] = 100 * (i + 1); } da = 3.0; BLAS1D.daxpy(3, da, x, 2, ref y, 1); Console.WriteLine(""); Console.WriteLine(" DAXPY ( 3, " + da + ", X, 2, Y, 1 )"); Console.WriteLine(""); Console.WriteLine(" Y ="); Console.WriteLine(""); for (int i = 0; i < N; i++) { Console.WriteLine(" " + (i + 1).ToString(CultureInfo.InvariantCulture).PadLeft(6) + " " + y[i].ToString(CultureInfo.InvariantCulture).PadLeft(14) + ""); } for (int i = 0; i < N; i++) { y[i] = 100 * (i + 1); } da = -4.0; BLAS1D.daxpy(3, da, x, 1, ref y, 2); Console.WriteLine(""); Console.WriteLine(" DAXPY ( 3, " + da + ", X, 1, Y, 2 )"); Console.WriteLine(""); Console.WriteLine(" Y ="); Console.WriteLine(""); for (int i = 0; i < N; i++) { Console.WriteLine(" " + (i + 1).ToString(CultureInfo.InvariantCulture).PadLeft(6) + " " + y[i].ToString(CultureInfo.InvariantCulture).PadLeft(14) + ""); } }
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); }