/* * lu_condest.c * * Copyright (C) 2016-2018 ERGO-Code * * LINPACK condition number estimate * */ #include "lu_internal.h" /* * lu_condest() * * Given m-by-m matrix U such that U[perm,perm] is upper triangular, * return estimate for 1-norm condition number of U. * If @norm is not NULL, it holds the 1-norm of the matrix on return. * If @norminv is not NULL, it holds the estimated 1-norm of the inverse on * return. * * The other function arguments are the same as in lu_normest(). * */ double lu_condest( lu_int m, const lu_int *Ubegin, const lu_int *Ui, const double *Ux, const double *pivot, const lu_int *perm, int upper, double *work, double *norm, double *norminv) { lu_int j, p; double Unorm, Uinvnorm; /* compute 1-norm of U */ Unorm = 0; for (j = 0; j < m; j++) { double colsum = pivot ? fabs(pivot[j]) : 1; for (p = Ubegin[j]; Ui[p] >= 0; p++) colsum += fabs(Ux[p]); Unorm = fmax(Unorm, colsum); } /* estimate 1-norm of U^{-1} */ Uinvnorm = lu_normest(m, Ubegin, Ui, Ux, pivot, perm, upper, work); if (norm) *norm = Unorm; if (norminv) *norminv = Uinvnorm; return Unorm * Uinvnorm; } /* * lu_normest() * * Given m-by-m matrix U such that U[perm,perm] is triangular, * estimate 1-norm of U^{-1} by computing * * U'x = b, Uy = x, normest = max{norm(y)_1/norm(x)_1, norm(x)_inf}, * * where the entries of b are +/-1 chosen dynamically to make x large. * The method is described in [1]. * * @Ubegin, @Ui, @Ux matrix U in compressed column format without pivots, * columns are terminated by a negative index * @pivot pivot elements by column index of U; NULL if unit pivots * @perm permutation to triangular form; NULL if identity * @upper nonzero if permuted matrix is upper triangular; zero if lower * @work size m workspace, uninitialized on entry/return * * Return: estimate for 1-norm of U^{-1} * * [1] I. Duff, A. Erisman, J. Reid, "Direct Methods for Sparse Matrices" * */ double lu_normest( lu_int m, const lu_int *Ubegin, const lu_int *Ui, const double *Ux, const double *pivot, const lu_int *perm, int upper, double *work) { lu_int i, j, k, kbeg, kend, kinc, p; double x1norm, xinfnorm, y1norm, temp; x1norm = 0; xinfnorm = 0; if (upper) { kbeg = 0; kend = m; kinc = 1; } else { kbeg = m-1; kend = -1; kinc = -1; } for (k = kbeg; k != kend; k += kinc) { j = perm ? perm[k] : k; temp = 0; for (p = Ubegin[j]; (i = Ui[p]) >= 0; p++) temp -= work[i] * Ux[p]; temp += temp >= 0 ? 1 : -1; /* choose b[i] = 1 or b[i] = -1 */ if (pivot) temp /= pivot[j]; work[j] = temp; x1norm += fabs(temp); xinfnorm = fmax(xinfnorm, fabs(temp)); } y1norm = 0; if (upper) { kbeg = m-1; kend = -1; kinc = -1; } else { kbeg = 0; kend = m; kinc = 1; } for (k = kbeg; k != kend; k += kinc) { j = perm ? perm[k] : k; if (pivot) work[j] /= pivot[j]; temp = work[j]; for (p = Ubegin[j]; (i = Ui[p]) >= 0; p++) work[i] -= temp * Ux[p]; y1norm += fabs(temp); } return fmax(y1norm/x1norm, xinfnorm); }