VEC *LUTsolve(const MAT *LU, PERM *pivot, const VEC *b, VEC *x) #endif { if ( ! LU || ! b || ! pivot ) error(E_NULL,"LUTsolve"); if ( LU->m != LU->n || LU->n != b->dim ) error(E_SIZES,"LUTsolve"); x = v_copy(b,x); UTsolve(LU,x,x,0.0); /* explicit diagonal */ LTsolve(LU,x,x,1.0); /* implicit diagonal = 1 */ pxinv_vec(pivot,x,x); /* x := P^T.tmp */ return (x); }
double QRcondest(const MAT *QR) #endif { STATIC VEC *y=VNULL; Real norm1, norm2, sum, tmp1, tmp2; int i, j, limit; if ( QR == MNULL ) error(E_NULL,"QRcondest"); limit = min(QR->m,QR->n); for ( i = 0; i < limit; i++ ) if ( QR->me[i][i] == 0.0 ) return HUGE_VAL; y = v_resize(y,limit); MEM_STAT_REG(y,TYPE_VEC); /* use the trick for getting a unit vector y with ||R.y||_inf small from the LU condition estimator */ for ( i = 0; i < limit; i++ ) { sum = 0.0; for ( j = 0; j < i; j++ ) sum -= QR->me[j][i]*y->ve[j]; sum -= (sum < 0.0) ? 1.0 : -1.0; y->ve[i] = sum / QR->me[i][i]; } UTmlt(QR,y,y); /* now apply inverse power method to R^T.R */ for ( i = 0; i < 3; i++ ) { tmp1 = v_norm2(y); sv_mlt(1/tmp1,y,y); UTsolve(QR,y,y,0.0); tmp2 = v_norm2(y); sv_mlt(1/v_norm2(y),y,y); Usolve(QR,y,y,0.0); } /* now compute approximation for ||R^{-1}||_2 */ norm1 = sqrt(tmp1)*sqrt(tmp2); /* now use complementary approach to compute approximation to ||R||_2 */ for ( i = limit-1; i >= 0; i-- ) { sum = 0.0; for ( j = i+1; j < limit; j++ ) sum += QR->me[i][j]*y->ve[j]; y->ve[i] = (sum >= 0.0) ? 1.0 : -1.0; y->ve[i] = (QR->me[i][i] >= 0.0) ? y->ve[i] : - y->ve[i]; } /* now apply power method to R^T.R */ for ( i = 0; i < 3; i++ ) { tmp1 = v_norm2(y); sv_mlt(1/tmp1,y,y); Umlt(QR,y,y); tmp2 = v_norm2(y); sv_mlt(1/tmp2,y,y); UTmlt(QR,y,y); } norm2 = sqrt(tmp1)*sqrt(tmp2); /* printf("QRcondest: norm1 = %g, norm2 = %g\n",norm1,norm2); */ #ifdef THREADSAFE V_FREE(y); #endif return norm1*norm2; }