⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spfactor.c

📁 ngspice又一个电子CAD仿真软件代码.功能更全
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  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. *//* *  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. */#include <assert.h>#define spINSIDE_SPARSE#include "spconfig.h"#include "spmatrix.h"#include "spdefs.h"/* * Function declarations */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 );/* *  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>  (int) *      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  (int) *      Flag that indicates whether reordering is required. * *  >>> Possible errors: *  spNO_MEMORY *  spSINGULAR *  spSMALL_PIVOT *  Error is cleared in this function. */intspOrderAndFactor(void *eMatrix, RealNumber RHS[], RealNumber RelThreshold,		 RealNumber AbsThreshold, int DiagPivoting){    MatrixPtr  Matrix = (MatrixPtr)eMatrix;    ElementPtr  pPivot;    int  Step, Size, ReorderingRequired;    ElementPtr SearchForPivot();    RealNumber LargestInCol, FindLargestInCol();    /* Begin `spOrderAndFactor'. */    assert( IS_VALID(Matrix) && !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 (!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 (!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(!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 (!Matrix->RowsLinked)            spcLinkRows( Matrix );        if (!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(void *eMatrix){    MatrixPtr  Matrix = (MatrixPtr)eMatrix;    ElementPtr  pElement;    ElementPtr  pColumn;    int  Step, Size;    RealNumber Mult;    /* Begin `spFactor'. */    assert( IS_VALID(Matrix) && !Matrix->Factored);    if (Matrix->NeedsOrdering)    {	return spOrderAndFactor( eMatrix, (RealVector)NULL,                                 0.0, 0.0, DIAG_PIVOTING_AS_DEFAULT );    }    if (!Matrix->Partitioned) spPartition( eMatrix, spDEFAULT_PARTITION );    if (Matrix->Complex)	return FactorComplexMatrix( Matrix );    Size = Matrix->Size;    if (Matrix->Diag[1]->Real == 0.0) return ZeroPivot( Matrix, 1 );    Matrix->Diag[1]->Real = 1.0 / Matrix->Diag[1]->Real;    /* Start factorization. */    for (Step = 2; Step <= Size; Step++)    {	if (Matrix->DoRealDirect[Step])        {	    /* Update column using direct addressing scatter-gather. */            RealNumber *Dest = (RealNumber *)Matrix->Intermediate;	    /* Scatter. */            pElement = Matrix->FirstInCol[Step];            while (pElement != NULL)            {		Dest[pElement->Row] = pElement->Real;                pElement = pElement->NextInCol;            }	    /* Update column. */            pColumn = Matrix->FirstInCol[Step];            while (pColumn->Row < Step)            {		pElement = Matrix->Diag[pColumn->Row];                pColumn->Real = Dest[pColumn->Row] * pElement->Real;                while ((pElement = pElement->NextInCol) != NULL)                    Dest[pElement->Row] -= pColumn->Real * pElement->Real;                pColumn = pColumn->NextInCol;            }	    /* Gather. */            pElement = Matrix->Diag[Step]->NextInCol;            while (pElement != NULL)            {		pElement->Real = Dest[pElement->Row];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -