📄 sputils.c
字号:
pElement = pElement->NextInCol;
}
T[I] *= pPivot->Real;
if (ABS(T[I]) > SLACK)
{ ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) );
for (K = Size; K > 0; K--) T[K] *= ScaleFactor;
ASy *= ScaleFactor;
}
}
/* Compute 1-norm of T, which now contains z. */
for (ASz = 0.0, I = Size; I > 0; I--) ASz += ABS(T[I]);
#if NOT spCOMPLEX
FREE( Tm );
#endif
Linpack = ASy / ASz;
OLeary = E / MaxY;
InvNormOfInverse = MIN( Linpack, OLeary );
return InvNormOfInverse / NormOfMatrix;
#endif /* REAL */
}
#if spCOMPLEX
/*
* ESTIMATE CONDITION NUMBER
*
* Complex version of spCondition().
*
* >>> Returns:
* The reciprocal of the condition number.
*
* >>> Arguments:
* Matrix <input> (MatrixPtr)
* Pointer to the matrix.
* NormOfMatrix <input> (RealNumber)
* The L-infinity norm of the unfactored matrix as computed by
* spNorm().
* pError <output> (int *)
* Used to return error code.
*
* >>> Possible errors:
* spNO_MEMORY
*/
static RealNumber
ComplexCondition(
MatrixPtr Matrix,
RealNumber NormOfMatrix,
int *pError
)
{
register ElementPtr pElement;
register ComplexVector T, Tm;
register int I, K, Row;
ElementPtr pPivot;
int Size;
RealNumber E, Em, ASp, ASm, ASw, ASy, ASv, ASz, MaxY, ScaleFactor;
RealNumber Linpack, OLeary, InvNormOfInverse;
ComplexNumber Wp, Wm;
/* Begin `ComplexCondition'. */
Size = Matrix->Size;
T = (ComplexVector)Matrix->Intermediate;
Tm = ALLOC( ComplexNumber, Size+1 );
if (Tm == NULL)
{ *pError = spNO_MEMORY;
return 0.0;
}
for (I = Size; I > 0; I--) T[I].Real = T[I].Imag = 0.0;
/*
* Part 1. Ay = e.
* Solve Ay = LUy = e where e consists of +1 and -1 terms with the sign
* chosen to maximize the size of w in Lw = e. Since the terms in w can
* get very large, scaling is used to avoid overflow.
*/
/* Forward elimination. Solves Lw = e while choosing e. */
E = 1.0;
for (I = 1; I <= Size; I++)
{ pPivot = Matrix->Diag[I];
if (T[I].Real < 0.0) Em = -E; else Em = E;
Wm = T[I];
Wm.Real += Em;
ASm = CMPLX_1_NORM( Wm );
CMPLX_MULT_ASSIGN( Wm, *pPivot );
if (CMPLX_1_NORM(Wm) > SLACK)
{ ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(Wm) );
for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor );
E *= ScaleFactor;
Em *= ScaleFactor;
ASm *= ScaleFactor;
SCLR_MULT_ASSIGN( Wm, ScaleFactor );
}
Wp = T[I];
Wp.Real -= Em;
ASp = CMPLX_1_NORM( Wp );
CMPLX_MULT_ASSIGN( Wp, *pPivot );
/* Update T for both values of W, minus value is placed in Tm. */
pElement = pPivot->NextInCol;
while (pElement != NULL)
{ Row = pElement->Row;
/* Cmplx expr: Tm[Row] = T[Row] - (Wp * *pElement). */
CMPLX_MULT_SUBT( Tm[Row], Wm, *pElement, T[Row] );
/* Cmplx expr: T[Row] -= Wp * *pElement. */
CMPLX_MULT_SUBT_ASSIGN( T[Row], Wm, *pElement );
ASp += CMPLX_1_NORM(T[Row]);
ASm += CMPLX_1_NORM(Tm[Row]);
pElement = pElement->NextInCol;
}
/* If minus value causes more growth, overwrite T with its values. */
if (ASm > ASp)
{ T[I] = Wm;
pElement = pPivot->NextInCol;
while (pElement != NULL)
{ T[pElement->Row] = Tm[pElement->Row];
pElement = pElement->NextInCol;
}
}
else T[I] = Wp;
}
/* Compute 1-norm of T, which now contains w, and scale ||T|| to 1/SLACK. */
for (ASw = 0.0, I = Size; I > 0; I--) ASw += CMPLX_1_NORM(T[I]);
ScaleFactor = 1.0 / (SLACK * ASw);
if (ScaleFactor < 0.5)
{ for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor );
E *= ScaleFactor;
}
/* Backward Substitution. Solves Uy = w.*/
for (I = Size; I >= 1; I--)
{ pElement = Matrix->Diag[I]->NextInRow;
while (pElement != NULL)
{ /* Cmplx expr: T[I] -= T[pElement->Col] * *pElement. */
CMPLX_MULT_SUBT_ASSIGN( T[I], T[pElement->Col], *pElement );
pElement = pElement->NextInRow;
}
if (CMPLX_1_NORM(T[I]) > SLACK)
{ ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(T[I]) );
for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor );
E *= ScaleFactor;
}
}
/* Compute 1-norm of T, which now contains y, and scale ||T|| to 1/SLACK. */
for (ASy = 0.0, I = Size; I > 0; I--) ASy += CMPLX_1_NORM(T[I]);
ScaleFactor = 1.0 / (SLACK * ASy);
if (ScaleFactor < 0.5)
{ for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor );
ASy = 1.0 / SLACK;
E *= ScaleFactor;
}
/* Compute infinity-norm of T for O'Leary's estimate. */
for (MaxY = 0.0, I = Size; I > 0; I--)
if (MaxY < CMPLX_1_NORM(T[I])) MaxY = CMPLX_1_NORM(T[I]);
/*
* Part 2. A* z = y where the * represents the transpose.
* Recall that A = LU implies A* = U* L*.
*/
/* Forward elimination, U* v = y. */
for (I = 1; I <= Size; I++)
{ pElement = Matrix->Diag[I]->NextInRow;
while (pElement != NULL)
{ /* Cmplx expr: T[pElement->Col] -= T[I] * *pElement. */
CMPLX_MULT_SUBT_ASSIGN( T[pElement->Col], T[I], *pElement );
pElement = pElement->NextInRow;
}
if (CMPLX_1_NORM(T[I]) > SLACK)
{ ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(T[I]) );
for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor );
ASy *= ScaleFactor;
}
}
/* Compute 1-norm of T, which now contains v, and scale ||T|| to 1/SLACK. */
for (ASv = 0.0, I = Size; I > 0; I--) ASv += CMPLX_1_NORM(T[I]);
ScaleFactor = 1.0 / (SLACK * ASv);
if (ScaleFactor < 0.5)
{ for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor );
ASy *= ScaleFactor;
}
/* Backward Substitution, L* z = v. */
for (I = Size; I >= 1; I--)
{ pPivot = Matrix->Diag[I];
pElement = pPivot->NextInCol;
while (pElement != NULL)
{ /* Cmplx expr: T[I] -= T[pElement->Row] * *pElement. */
CMPLX_MULT_SUBT_ASSIGN( T[I], T[pElement->Row], *pElement );
pElement = pElement->NextInCol;
}
CMPLX_MULT_ASSIGN( T[I], *pPivot );
if (CMPLX_1_NORM(T[I]) > SLACK)
{ ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(T[I]) );
for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor );
ASy *= ScaleFactor;
}
}
/* Compute 1-norm of T, which now contains z. */
for (ASz = 0.0, I = Size; I > 0; I--) ASz += CMPLX_1_NORM(T[I]);
FREE( Tm );
Linpack = ASy / ASz;
OLeary = E / MaxY;
InvNormOfInverse = MIN( Linpack, OLeary );
return InvNormOfInverse / NormOfMatrix;
}
#endif /* spCOMPLEX */
/*!
* Computes the L-infinity norm of an unfactored matrix. It is a fatal
* error to pass this routine a factored matrix.
*
* \return
* The largest absolute row sum of matrix.
*
* \param eMatrix
* Pointer to the matrix.
*/
spREAL
spNorm( spMatrix eMatrix )
{
MatrixPtr Matrix = (MatrixPtr)eMatrix;
register ElementPtr pElement;
register int I;
RealNumber Max = 0.0, AbsRowSum;
/* Begin `spNorm'. */
ASSERT_IS_SPARSE( Matrix );
ASSERT_NO_ERRORS( Matrix );
ASSERT_IS_NOT_FACTORED( Matrix );
if (NOT Matrix->RowsLinked) spcLinkRows( Matrix );
/* Compute row sums. */
#if REAL
if (NOT Matrix->Complex)
{ for (I = Matrix->Size; I > 0; I--)
{ pElement = Matrix->FirstInRow[I];
AbsRowSum = 0.0;
while (pElement != NULL)
{ AbsRowSum += ABS( pElement->Real );
pElement = pElement->NextInRow;
}
if (Max < AbsRowSum) Max = AbsRowSum;
}
}
#endif
#if spCOMPLEX
if (Matrix->Complex)
{ for (I = Matrix->Size; I > 0; I--)
{ pElement = Matrix->FirstInRow[I];
AbsRowSum = 0.0;
while (pElement != NULL)
{ AbsRowSum += CMPLX_1_NORM( *pElement );
pElement = pElement->NextInRow;
}
if (Max < AbsRowSum) Max = AbsRowSum;
}
}
#endif
return Max;
}
#endif /* CONDITION */
#if STABILITY
/*!
* This routine, along with spRoundoff(), are used to gauge the stability of a
* factorization. If the factorization is determined to be too unstable,
* then the matrix should be reordered. The routines compute quantities
* that are needed in the computation of a bound on the error attributed
* to any one element in the matrix during the factorization. In other
* words, there is a matrix \f$ E = [e_{ij}] \f$ of error terms such that
* \f$ A+E = LU \f$. This routine finds a bound on \f$ |e_{ij}| \f$.
* Erisman & Reid [1] showed that \f$ |e_{ij}| < 3.01 u \rho m_{ij} \f$,
* where \f$ u \f$ is the machine rounding unit,
* \f$ \rho = \max a_{ij} \f$ where the max is taken over every row \f$ i \f$,
* column \f$ j \f$, and step \f$ k \f$, and \f$ m_{ij} \f$ is the number
* of multiplications required in the computation of \f$ l_{ij} \f$ if
* \f$ i > j \f$ or \f$ u_{ij} \f$ otherwise. Barlow [2] showed that
* \f$ \rho < \max_i || l_i ||_p \max_j || u_j ||_q \f$ where
* \f$ 1/p + 1/q = 1 \f$.
*
* spLargestElement() finds the magnitude on the largest element in the
* matrix. If the matrix has not yet been factored, the largest
* element is found by direct search. If the matrix is factored, a
* bound on the largest element in any of the reduced submatrices is
* computed using Barlow with \f$ p = \infty \f$ and \f$ q = 1 \f$.
* The ratio of these
* two numbers is the growth, which can be used to determine if the
* pivoting order is adequate. A large growth implies that
* considerable error has been made in the factorization and that it
* is probably a good idea to reorder the matrix. If a large growth
* in encountered after using spFactor(), reconstruct the matrix and
* refactor using spOrderAndFactor(). If a large growth is
* encountered after using spOrderAndFactor(), refactor using
* spOrderAndFactor() with the pivot threshold increased, say to 0.1.
*
* Using only the size of the matrix as an upper bound on \f$ m_{ij} \f$ and
* Barlow's bound, the user can estimate the size of the matrix error
* terms \f$ e_{ij} \f$ using the bound of Erisman and Reid. spRoundoff()
* computes a tighter bound (with more work) based on work by Gear
* [3], \f$ |e_{ij}| < 1.01 u \rho (t c^3 + (1 + t)c^2) \f$ where
* \f$ t \f$ is the threshold and \f$ c \f$ is the maximum number of
* off-diagonal elements in any row of \f$ L \f$. The expensive part
* of computing this bound is determining the maximum number of
* off-diagonals in \f$ L \f$, which changes
* only when the order of the matrix changes. This number is computed
* and saved, and only recomputed if the matrix is reordered.
*
* [1] A. M. Erisman, J. K. Reid. Monitoring the stability of the
* triangular factorization of a sparse matrix. Numerische
* Mathematik. Vol. 22, No. 3, 1974, pp 183-186.
*
* [2] J. L. Barlow. A note on monitoring the stability of triangular
* decomposition of sparse matrices. "SIAM Journal of Scientific
* and Statistical Computing." Vol. 7, No. 1, January 1986, pp 166-168.
*
* [3] I. S. Duff, A. M. Erisman, J. K. Reid. "Direct Methods for Sparse
* Matrices." Oxford 1986. pp 99.
*
* \return
* If matrix is not factored, returns the magnitude of the largest element in
* the matrix. If the matrix is factored, a bound on the magnitude of the
* largest element in any of the reduced submatrices is returned.
*
* \param eMatrix
* Pointer to the matrix.
*/
spREAL
spLargestElement( spMatrix eMatrix )
{
MatrixPtr Matrix = (MatrixPtr)eMatrix;
register int I;
RealNumber Mag, AbsColSum, Max = 0.0, MaxRow = 0.0, MaxCol = 0.0;
RealNumber Pivot;
#if spCOMPLEX
ComplexNumber cPivot;
#endif
register ElementPtr pElement, pDiag;
/* Begin `spLargestElement'. */
ASSERT_IS_SPARSE( Matrix );
#if REAL
if (Matrix->Factored AND NOT Matrix->Complex)
{ if (Matrix->Error == spSINGULAR) return 0.0;
/* Find the bound on the size of the largest element over all factorization. */
for (I = 1; I <= Matrix->Size; I++)
{ pDiag = Matrix->Diag[I];
/* Lower triangular matrix. */
Pivot = 1.0 / pDiag->Real;
Mag = ABS( Pivot );
if (Mag > MaxRow) MaxRow = Mag;
pElement = Matrix->FirstInRow[I];
while (pElement != pDiag)
{ Mag = ABS( pElement->Real );
if (Mag > MaxRow) MaxRow = Mag;
pElement = pElement->NextInRow;
}
/* Upper triangular matrix. */
pElement = Matrix->FirstInCol[I];
AbsColSum = 1.0; /* Diagonal of U is unity. */
while (pElement != pDiag)
{ AbsColSum += ABS( pElement->Real );
pElement = pElement->NextInCol;
}
if (AbsColSum > MaxCol) MaxCol = AbsColSum;
}
}
else if (NOT Matrix->Complex)
{ for (I = 1; I <= Matrix->Size; I++)
{ pElement = Matrix->FirstInCol[I];
while (pElement != NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -