📄 spfactor.c
字号:
/* * MATRIX FACTORIZATION MODULE * * Author: Advising Professor: * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli * UC Berkeley * * This file contains the routines to factor the matrix into LU form. * * >>> User accessible functions contained in this file: * spOrderAndFactor * spFactor * spPartition * * >>> Other functions contained in this file: * FactorComplexMatrix spcCreateInternalVectors * CountMarkowitz MarkowitzProducts * SearchForPivot SearchForSingleton * QuicklySearchDiagonal SearchDiagonal * SearchEntireMatrix FindLargestInCol * FindBiggestInColExclude ExchangeRowsAndCols * spcRowExchange spcColExchange * ExchangeColElements ExchangeRowElements * RealRowColElimination ComplexRowColElimination * UpdateMarkowitzNumbers CreateFillin * MatrixIsSingular ZeroPivot * WriteStatus *//* * Revision and copyright information. * * Copyright (c) 1985,86,87,88,89,90 * by Kenneth S. Kundert and the University of California. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the copyright notices appear in all copies and * supporting documentation and that the authors and the University of * California are properly credited. The authors and the University of * California make no representations as to the suitability of this * software for any purpose. It is provided `as is', without express * or implied warranty. */#ifdef notdefstatic char copyright[] = "Sparse1.3: Copyright (c) 1985,86,87,88,89,90 by Kenneth S. Kundert";static char RCSid[] = "@(#)$Header: spFactor.c,v 1.3 88/06/24 05:01:12 kundert Exp $";#endif/* * IMPORTS * * >>> Import descriptions: * spConfig.h * Macros that customize the sparse matrix routines. * spMatrix.h * Macros and declarations to be imported by the user. * spDefs.h * Matrix type and macro definitions for the sparse matrix routines. */#define spINSIDE_SPARSE#include "spconfig.h"#include "spmatrix.h"#include "spdefs.h"/* * Function declarations */#ifdef __STDC__static int FactorComplexMatrix( MatrixPtr );static void CountMarkowitz( MatrixPtr, RealVector, int );static void MarkowitzProducts( MatrixPtr, int );static ElementPtr SearchForPivot( MatrixPtr, int, int );static ElementPtr SearchForSingleton( MatrixPtr, int );static ElementPtr QuicklySearchDiagonal( MatrixPtr, int );static ElementPtr SearchDiagonal( MatrixPtr, int );static ElementPtr SearchEntireMatrix( MatrixPtr, int );static RealNumber FindLargestInCol( ElementPtr );static RealNumber FindBiggestInColExclude( MatrixPtr, ElementPtr, int );static void ExchangeRowsAndCols( MatrixPtr, ElementPtr, int );static void ExchangeColElements( MatrixPtr, int, ElementPtr, int, ElementPtr, int );static void ExchangeRowElements( MatrixPtr, int, ElementPtr, int, ElementPtr, int );static void RealRowColElimination( MatrixPtr, ElementPtr );static void ComplexRowColElimination( MatrixPtr, ElementPtr );static void UpdateMarkowitzNumbers( MatrixPtr, ElementPtr );static ElementPtr CreateFillin( MatrixPtr, int, int );static int MatrixIsSingular( MatrixPtr, int );static int ZeroPivot( MatrixPtr, int );static void WriteStatus( MatrixPtr, int );#else /* __STDC__ */static int FactorComplexMatrix();static void CountMarkowitz();static void MarkowitzProducts();static ElementPtr SearchForPivot();static ElementPtr SearchForSingleton();static ElementPtr QuicklySearchDiagonal();static ElementPtr SearchDiagonal();static ElementPtr SearchEntireMatrix();static RealNumber FindLargestInCol();static RealNumber FindBiggestInColExclude();static void ExchangeRowsAndCols();static void ExchangeColElements();static void ExchangeRowElements();static void RealRowColElimination();static void ComplexRowColElimination();static void UpdateMarkowitzNumbers();static ElementPtr CreateFillin();static int MatrixIsSingular();static int ZeroPivot();static void WriteStatus();#endif /* __STDC__ *//* * ORDER AND FACTOR MATRIX * * This routine chooses a pivot order for the matrix and factors it * into LU form. It handles both the initial factorization and subsequent * factorizations when a reordering is desired. This is handled in a manner * that is transparent to the user. The routine uses a variation of * Gauss's method where the pivots are associated with L and the * diagonal terms of U are one. * * >>> Returned: * The error code is returned. Possible errors are listed below. * * >>> Arguments: * Matrix <input> (char *) * Pointer to matrix. * RHS <input> (RealVector) * Representative right-hand side vector that is used to determine * pivoting order when the right hand side vector is sparse. If * RHS is a NULL pointer then the RHS vector is assumed to * be full and it is not used when determining the pivoting * order. * RelThreshold <input> (RealNumber) * This number determines what the pivot relative threshold will * be. It should be between zero and one. If it is one then the * pivoting method becomes complete pivoting, which is very slow * and tends to fill up the matrix. If it is set close to zero * the pivoting method becomes strict Markowitz with no * threshold. The pivot threshold is used to eliminate pivot * candidates that would cause excessive element growth if they * were used. Element growth is the cause of roundoff error. * Element growth occurs even in well-conditioned matrices. * Setting the RelThreshold large will reduce element growth and * roundoff error, but setting it too large will cause execution * time to be excessive and will result in a large number of * fill-ins. If this occurs, accuracy can actually be degraded * because of the large number of operations required on the * matrix due to the large number of fill-ins. A good value seems * to be 0.001. The default is chosen by giving a value larger * than one or less than or equal to zero. This value should be * increased and the matrix resolved if growth is found to be * excessive. Changing the pivot threshold does not improve * performance on matrices where growth is low, as is often the * case with ill-conditioned matrices. Once a valid threshold is * given, it becomes the new default. The default value of * RelThreshold was choosen for use with nearly diagonally * dominant matrices such as node- and modified-node admittance * matrices. For these matrices it is usually best to use * diagonal pivoting. For matrices without a strong diagonal, it * is usually best to use a larger threshold, such as 0.01 or * 0.1. * AbsThreshold <input> (RealNumber) * The absolute magnitude an element must have to be considered * as a pivot candidate, except as a last resort. This number * should be set significantly smaller than the smallest diagonal * element that is is expected to be placed in the matrix. If * there is no reasonable prediction for the lower bound on these * elements, then AbsThreshold should be set to zero. * AbsThreshold is used to reduce the possibility of choosing as a * pivot an element that has suffered heavy cancellation and as a * result mainly consists of roundoff error. Once a valid * threshold is given, it becomes the new default. * DiagPivoting <input> (BOOLEAN) * A flag indicating that pivot selection should be confined to the * diagonal if possible. If DiagPivoting is nonzero and if * DIAGONAL_PIVOTING is enabled pivots will be chosen only from * the diagonal unless there are no diagonal elements that satisfy * the threshold criteria. Otherwise, the entire reduced * submatrix is searched when looking for a pivot. The diagonal * pivoting in Sparse is efficient and well refined, while the * off-diagonal pivoting is not. For symmetric and near symmetric * matrices, it is best to use diagonal pivoting because it * results in the best performance when reordering the matrix and * when factoring the matrix without ordering. If there is a * considerable amount of nonsymmetry in the matrix, then * off-diagonal pivoting may result in a better equation ordering * simply because there are more pivot candidates to choose from. * A better ordering results in faster subsequent factorizations. * However, the initial pivot selection process takes considerably * longer for off-diagonal pivoting. * * >>> Local variables: * pPivot (ElementPtr) * Pointer to the element being used as a pivot. * ReorderingRequired (BOOLEAN) * Flag that indicates whether reordering is required. * * >>> Possible errors: * spNO_MEMORY * spSINGULAR * spSMALL_PIVOT * Error is cleared in this function. */intspOrderAndFactor( eMatrix, RHS, RelThreshold, AbsThreshold, DiagPivoting )char *eMatrix;RealNumber RHS[], RelThreshold, AbsThreshold;BOOLEAN DiagPivoting;{MatrixPtr Matrix = (MatrixPtr)eMatrix;ElementPtr pPivot;int Step, Size, ReorderingRequired;ElementPtr SearchForPivot();RealNumber LargestInCol, FindLargestInCol();/* Begin `spOrderAndFactor'. */ ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored); Matrix->Error = spOKAY; Size = Matrix->Size; if (RelThreshold <= 0.0) RelThreshold = Matrix->RelThreshold; if (RelThreshold > 1.0) RelThreshold = Matrix->RelThreshold; Matrix->RelThreshold = RelThreshold; if (AbsThreshold < 0.0) AbsThreshold = Matrix->AbsThreshold; Matrix->AbsThreshold = AbsThreshold; ReorderingRequired = NO; if (NOT Matrix->NeedsOrdering) {/* Matrix has been factored before and reordering is not required. */ for (Step = 1; Step <= Size; Step++) { pPivot = Matrix->Diag[Step]; LargestInCol = FindLargestInCol(pPivot->NextInCol); if ((LargestInCol * RelThreshold < ELEMENT_MAG(pPivot))) { if (Matrix->Complex) ComplexRowColElimination( Matrix, pPivot ); else RealRowColElimination( Matrix, pPivot ); } else { ReorderingRequired = YES; break; /* for loop */ } } if (NOT ReorderingRequired) goto Done; else {/* * A pivot was not large enough to maintain accuracy, * so a partial reordering is required. */#if (ANNOTATE >= ON_STRANGE_BEHAVIOR) printf("Reordering, Step = %1d\n", Step);#endif } } /* End of if(NOT Matrix->NeedsOrdering) */ else {/* * This is the first time the matrix has been factored. These few statements * indicate to the rest of the code that a full reodering is required rather * than a partial reordering, which occurs during a failure of a fast * factorization. */ Step = 1; if (NOT Matrix->RowsLinked) spcLinkRows( Matrix ); if (NOT Matrix->InternalVectorsAllocated) spcCreateInternalVectors( Matrix ); if (Matrix->Error >= spFATAL) return Matrix->Error; }/* Form initial Markowitz products. */ CountMarkowitz( Matrix, RHS, Step ); MarkowitzProducts( Matrix, Step ); Matrix->MaxRowCountInLowerTri = -1;/* Perform reordering and factorization. */ for (; Step <= Size; Step++) { pPivot = SearchForPivot( Matrix, Step, DiagPivoting ); if (pPivot == NULL) return MatrixIsSingular( Matrix, Step ); ExchangeRowsAndCols( Matrix, pPivot, Step ); if (Matrix->Complex) ComplexRowColElimination( Matrix, pPivot ); else RealRowColElimination( Matrix, pPivot ); if (Matrix->Error >= spFATAL) return Matrix->Error; UpdateMarkowitzNumbers( Matrix, pPivot );#if (ANNOTATE == FULL) WriteStatus( Matrix, Step );#endif }Done: Matrix->NeedsOrdering = NO; Matrix->Reordered = YES; Matrix->Factored = YES; return Matrix->Error;}/* * FACTOR MATRIX * * This routine is the companion routine to spOrderAndFactor(). * Unlike spOrderAndFactor(), spFactor() cannot change the ordering. * It is also faster than spOrderAndFactor(). The standard way of * using these two routines is to first use spOrderAndFactor() for the * initial factorization. For subsequent factorizations, spFactor() * is used if there is some assurance that little growth will occur * (say for example, that the matrix is diagonally dominant). If * spFactor() is called for the initial factorization of the matrix, * then spOrderAndFactor() is automatically called with the default * threshold. This routine uses "row at a time" LU factorization. * Pivots are associated with the lower triangular matrix and the * diagonals of the upper triangular matrix are ones. * * >>> Returned: * The error code is returned. Possible errors are listed below. * * >>> Arguments: * Matrix <input> (char *) * Pointer to matrix. * * >>> Possible errors: * spNO_MEMORY * spSINGULAR * spZERO_DIAG * spSMALL_PIVOT * Error is cleared in this function. */intspFactor( eMatrix )char *eMatrix;{MatrixPtr Matrix = (MatrixPtr)eMatrix;register ElementPtr pElement;register ElementPtr pColumn;register int Step, Size;RealNumber Mult;/* Begin `spFactor'. */ ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored); if (Matrix->NeedsOrdering) { return spOrderAndFactor( eMatrix, (RealVector)NULL,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -