diff --git a/src/include/ngspice/spmatrix.h b/src/include/ngspice/spmatrix.h index 33780a56e..10159d015 100644 --- a/src/include/ngspice/spmatrix.h +++ b/src/include/ngspice/spmatrix.h @@ -1,9 +1,6 @@ -/* - * EXPORTS for sparse matrix routines with SPICE3. - * - * Author: Advising professor: - * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli - * UC Berkeley +/* EXPORTS for sparse matrix routines. */ +/*! + * \file * * This file contains definitions that are useful to the calling * program. In particular, this file contains error keyword @@ -13,25 +10,21 @@ * Also included is the type definitions for the various functions * available to the user. * - * This file is a modified version of spMatrix.h that is used when - * interfacing to Spice3. + * Objects that begin with the \a spc prefix are considered private + * and should not be used. + * + * \author + * Kenneth S. Kundert */ /* * Revision and copyright information. * - * Copyright (c) 1985,86,87,88,89,90 - * by Kenneth S. Kundert and the University of California. + * Copyright (c) 1985-2003 by Kenneth S. Kundert * - * 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. + * $Date: 2003/06/29 04:19:52 $ + * $Revision: 1.2 $ */ @@ -39,6 +32,17 @@ #ifndef spOKAY +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + */ + +#include "../../maths/sparse/spConfig.h" + + @@ -50,47 +54,54 @@ * changed under the condition that the codes for the nonfatal errors are * less than the code for spFATAL and similarly the codes for the fatal * errors are greater than that for spFATAL. - * - * >>> Error descriptions: - * spOKAY - * No error has occurred. - * spSMALL_PIVOT - * When reordering the matrix, no element was found which satisfies the - * threshold criteria. The largest element in the matrix was chosen - * as pivot. Non-fatal. - * spZERO_DIAG - * Fatal error. A zero was encountered on the diagonal the matrix. This - * does not necessarily imply that the matrix is singular. When this - * error occurs, the matrix should be reconstructed and factored using - * spOrderAndFactor(). - * spSINGULAR - * Fatal error. Matrix is singular, so no unique solution exists. - * spNO_MEMORY - * Fatal error. Indicates that not enough memory is available to handle - * the matrix. - * spPANIC - * Fatal error indicating that the routines are not prepared to - * handle the matrix that has been requested. This may occur when - * the matrix is specified to be real and the routines are not - * compiled for real matrices, or when the matrix is specified to - * be complex and the routines are not compiled to handle complex - * matrices. - * spFATAL - * Not an error flag, but rather the dividing line between fatal errors - * and warnings. */ -#include "ngspice/sperror.h" /* Spice error definitions. */ - /* Begin error macros. */ -#define spOKAY OK -#define spSMALL_PIVOT OK -#define spZERO_DIAG E_SINGULAR -#define spSINGULAR E_SINGULAR -#define spNO_MEMORY E_NOMEM -#define spPANIC E_BADMATRIX - -#define spFATAL E_BADMATRIX +#define spOKAY 0 /*!< + * Error code that indicates that no error has + * occurred. + */ +#define spSMALL_PIVOT 1 /*!< + * Non-fatal error code that indicates that, when + * reordering the matrix, no element was found that + * satisfies the absolute threshold criteria. The + * largest element in the matrix was chosen as pivot. + */ +#define spZERO_DIAG 2 /*!< + * Fatal error code that indicates that, a zero was + * encountered on the diagonal the matrix. This does + * not necessarily imply that the matrix is singular. + * When this error occurs, the matrix should be + * reconstructed and factored using + * spOrderAndFactor(). + */ +#define spSINGULAR 3 /*!< + * Fatal error code that indicates that, matrix is + * singular, so no unique solution exists. + */ +#define spMANGLED 4 /*!< + * Fatal error code that indicates that, matrix has + * been mangled, results of requested operation are + * garbage. + */ +#define spNO_MEMORY 5 /*!< + * Fatal error code that indicates that not enough + * memory is available. + */ +#define spPANIC 6 /*!< + * Fatal error code that indicates that the routines + * are not prepared to handle the matrix that has + * been requested. This may occur when the matrix + * is specified to be real and the routines are not + * compiled for real matrices, or when the matrix is + * specified to be complex and the routines are not + * compiled to handle complex matrices. + */ +#define spFATAL 2 /*!< + * Error code that is not an error flag, but rather + * the dividing line between fatal errors and + * warnings. + */ @@ -99,21 +110,18 @@ /* * KEYWORD DEFINITIONS - * - * Here we define what precision arithmetic Sparse will use. Double - * precision is suggested as being most appropriate for circuit - * simulation and for C. However, it is possible to change spREAL - * to a float for single precision arithmetic. Note that in C, single - * precision arithmetic is often slower than double precision. Sparse - * internally refers to spREALs as RealNumbers. - * - * Some C compilers, notably the old VMS compiler, do not handle the keyword - * "void" correctly. If this is true for your compiler, remove the - * comment delimiters from the redefinition of void to int below. */ -#define spREAL double -/* #define void int */ +#define spREAL double /*!< + * Defines the precision of the arithmetic used by + * \a Sparse will use. Double precision is suggested + * as being most appropriate for circuit simulation + * and for C. However, it is possible to change spREAL + * to a float for single precision arithmetic. Note + * that in C, single precision arithmetic is often + * slower than double precision. Sparse + * internally refers to spREALs as RealNumbers. + */ @@ -140,10 +148,32 @@ /* Begin partition keywords. */ -#define spDEFAULT_PARTITION 0 -#define spDIRECT_PARTITION 1 -#define spINDIRECT_PARTITION 2 -#define spAUTO_PARTITION 3 +#define spDEFAULT_PARTITION 0 /*!< + * Partition code for spPartition(). + * Indicates that the default partitioning + * mode should be used. + * \see spPartition() + */ +#define spDIRECT_PARTITION 1 /*!< + * Partition code for spPartition(). + * Indicates that all rows should be placed + * in the direct addressing partition. + * \see spPartition() + */ +#define spINDIRECT_PARTITION 2 /*!< + * Partition code for spPartition(). + * Indicates that all rows should be placed + * in the indirect addressing partition. + * \see spPartition() + */ +#define spAUTO_PARTITION 3 /*!< + * Partition code for spPartition(). + * Indicates that \a Sparse should chose + * the best partition for each row based + * on some simple rules. This is generally + * preferred. + * \see spPartition() + */ @@ -151,38 +181,33 @@ /* * MACRO FUNCTION DEFINITIONS - * - * >>> Macro descriptions: - * spADD_REAL_ELEMENT - * Macro function that adds data to a real element in the matrix by a - * pointer. - * spADD_IMAG_ELEMENT - * Macro function that adds data to a imaginary element in the matrix by - * a pointer. - * spADD_COMPLEX_ELEMENT - * Macro function that adds data to a complex element in the matrix by a - * pointer. - * spADD_REAL_QUAD - * Macro function that adds data to each of the four real matrix elements - * specified by the given template. - * spADD_IMAG_QUAD - * Macro function that adds data to each of the four imaginary matrix - * elements specified by the given template. - * spADD_COMPLEX_QUAD - * Macro function that adds data to each of the four complex matrix - * elements specified by the given template. */ /* Begin Macros. */ +/*! + * Macro function that adds data to a real element in the matrix by a pointer. + */ #define spADD_REAL_ELEMENT(element,real) *(element) += real +/*! + * Macro function that adds data to a imaginary element in the matrix by + * a pointer. + */ #define spADD_IMAG_ELEMENT(element,imag) *(element+1) += imag +/*! + * Macro function that adds data to a complex element in the matrix by + * a pointer. + */ #define spADD_COMPLEX_ELEMENT(element,real,imag) \ { *(element) += real; \ *(element+1) += imag; \ } +/*! + * Macro function that adds data to each of the four real matrix elements + * specified by the given template. + */ #define spADD_REAL_QUAD(template,real) \ { *((template).Element1) += real; \ *((template).Element2) += real; \ @@ -190,6 +215,10 @@ *((template).Element4Negated) -= real; \ } +/*! + * Macro function that adds data to each of the four imaginary matrix + * elements specified by the given template. + */ #define spADD_IMAG_QUAD(template,imag) \ { *((template).Element1+1) += imag; \ *((template).Element2+1) += imag; \ @@ -197,6 +226,10 @@ *((template).Element4Negated+1) -= imag; \ } +/*! + * Macro function that adds data to each of the four complex matrix + * elements specified by the given template. + */ #define spADD_COMPLEX_QUAD(template,real,imag) \ { *((template).Element1) += real; \ *((template).Element2) += real; \ @@ -212,33 +245,50 @@ + /* - * TYPE DEFINITION FOR COMPONENT TEMPLATE + * TYPE DEFINITION FOR EXTERNAL MATRIX ELEMENT REFERENCES * + * External type definitions for Sparse data objects. + */ + +/*! Declares the type of the a pointer to a matrix. */ +typedef spGenericPtr spMatrix; + +/*! Declares the type of the a pointer to a matrix element. */ +typedef spREAL spElement; + +/*! Declares the type of the Sparse error codes. */ +typedef int spError; + + + + + +/* TYPE DEFINITION FOR COMPONENT TEMPLATE */ +/*! * This data structure is used to hold pointers to four related elements in - * matrix. It is used in conjunction with the routines - * spGetAdmittance - * spGetQuad - * spGetOnes - * These routines stuff the structure which is later used by the spADD_QUAD - * macro functions above. It is also possible for the user to collect four - * pointers returned by spGetElement and stuff them into the template. - * The spADD_QUAD routines stuff data into the matrix in locations specified - * by Element1 and Element2 without changing the data. The data is negated - * before being placed in Element3 and Element4. + * matrix. It is used in conjunction with the routines spGetAdmittance(), + * spGetQuad(), and spGetOnes(). These routines stuff the structure which + * is later used by the \a spADD_QUAD macro functions above. It is also + * possible for the user to collect four pointers returned by spGetElement() + * and stuff them into the template. The \a spADD_QUAD routines stuff data + * into the matrix in locations specified by \a Element1 and \a Element2 + * without changing the data. The data is negated before being placed in + * \a Element3 and \a Element4. */ /* Begin `spTemplate'. */ struct spTemplate -{ spREAL *Element1 ; - spREAL *Element2 ; - spREAL *Element3Negated; - spREAL *Element4Negated; +{ spElement *Element1; + spElement *Element2; + spElement *Element3Negated; + spElement *Element4Negated; }; -typedef struct MatrixFrame *MatrixPtr; + /* @@ -249,49 +299,78 @@ typedef struct MatrixFrame *MatrixPtr; /* Begin function declarations. */ -extern void spClear( MatrixPtr ); -extern spREAL spCondition( MatrixPtr, spREAL, int* ); -extern MatrixPtr spCreate( int, int, int* ); -extern void spDeleteRowAndCol( MatrixPtr, int, int ); -extern void spDestroy( MatrixPtr); -extern int spElementCount( MatrixPtr ); -extern int spError( MatrixPtr ); -extern int spFactor( MatrixPtr ); -extern int spFileMatrix( MatrixPtr, char *, char *, int, int, int ); -extern int spFileStats( MatrixPtr, char *, char * ); -extern int spFillinCount( MatrixPtr ); -extern int spGetAdmittance( MatrixPtr, int, int, struct spTemplate* ); -extern spREAL *spFindElement(MatrixPtr Matrix, int Row, int Col ); -extern spREAL *spGetElement(MatrixPtr, int, int ); -extern void *spGetInitInfo( spREAL* ); -extern int spGetOnes( MatrixPtr, int, int, int, struct spTemplate* ); -extern int spGetQuad( MatrixPtr, int, int, int, int, struct spTemplate* ); -extern int spGetSize( MatrixPtr, int ); -extern int spInitialize(MatrixPtr, int (*pInit)(spREAL*, void *InitInfo, int, int Col)); -extern void spInstallInitInfo( spREAL*, void * ); -extern spREAL spLargestElement( MatrixPtr ); -extern void spMNA_Preorder( MatrixPtr ); -extern spREAL spNorm( MatrixPtr ); -extern int spOrderAndFactor(MatrixPtr, spREAL*, spREAL, spREAL, int ); -extern int spOriginalCount( MatrixPtr); -extern void spPartition( MatrixPtr, int ); -extern void spPrint(MatrixPtr, int, int, int ); -extern spREAL spPseudoCondition( MatrixPtr ); -extern spREAL spRoundoff( MatrixPtr, spREAL ); -extern void spScale( MatrixPtr, spREAL*, spREAL* ); -extern void spSetComplex( MatrixPtr ); -extern void spSetReal( MatrixPtr ); -extern void spStripFills( MatrixPtr ); -extern void spWhereSingular(MatrixPtr, int*, int* ); -extern void spConstMult(MatrixPtr, double); +spcEXTERN void spClear( spMatrix ); +spcEXTERN spREAL spCondition( spMatrix, spREAL, int* ); +spcEXTERN spMatrix spCreate( int, int, spError* ); +spcEXTERN void spDeleteRowAndCol( spMatrix, int, int ); +spcEXTERN void spDestroy( spMatrix ); +spcEXTERN int spElementCount( spMatrix ); +spcEXTERN int spOriginalCount( spMatrix ); +spcEXTERN spError spErrorState( spMatrix ); +#ifdef EOF + spcEXTERN void spErrorMessage( spMatrix, FILE*, char* ); +#else +# define spErrorMessage(a,b,c) spcFUNC_NEEDS_FILE(_spErrorMessage,stdio) +#endif + + +spcEXTERN spError spFactor( spMatrix ); +spcEXTERN int spFileMatrix( spMatrix, char*, char*, int, int, int ); +spcEXTERN int spFileStats( spMatrix, char*, char* ); +spcEXTERN int spFillinCount( spMatrix ); +spcEXTERN spElement *spFindElement( spMatrix, int, int ); +spcEXTERN spError spGetAdmittance( spMatrix, int, int, + struct spTemplate* ); +spcEXTERN spElement *spGetElement( spMatrix, int, int ); +spcEXTERN spGenericPtr spGetInitInfo( spElement* ); +spcEXTERN spError spGetOnes( spMatrix, int, int, int, + struct spTemplate* ); +spcEXTERN spError spGetQuad( spMatrix, int, int, int, int, + struct spTemplate* ); +spcEXTERN int spGetSize( spMatrix, int ); +spcEXTERN int spInitialize( spMatrix, int (*pInit)(spElement *, spGenericPtr, int, int) ); +spcEXTERN void spInstallInitInfo( spElement*, spGenericPtr ); +spcEXTERN spREAL spLargestElement( spMatrix ); +spcEXTERN void spMNA_Preorder( spMatrix ); +spcEXTERN spREAL spNorm( spMatrix ); +spcEXTERN spError spOrderAndFactor( spMatrix, spREAL[], spREAL, + spREAL, int ); +spcEXTERN void spPartition( spMatrix, int ); +spcEXTERN void spPrint( spMatrix, int, int, int ); +spcEXTERN spREAL spPseudoCondition( spMatrix ); +spcEXTERN spREAL spRoundoff( spMatrix, spREAL ); +spcEXTERN void spScale( spMatrix, spREAL[], spREAL[] ); +spcEXTERN void spSetComplex( spMatrix ); +spcEXTERN void spSetReal( spMatrix ); +spcEXTERN void spStripFills( spMatrix ); +spcEXTERN void spWhereSingular( spMatrix, int*, int* ); /* Functions with argument lists that are dependent on options. */ -extern void spDeterminant ( MatrixPtr, int*, spREAL*, spREAL* ); -extern int spFileVector( MatrixPtr, char * , spREAL*, spREAL*); -extern void spMultiply( MatrixPtr, spREAL*, spREAL*, spREAL*, spREAL* ); -extern void spMultTransposed(MatrixPtr,spREAL*,spREAL*,spREAL*,spREAL*); -extern void spSolve( MatrixPtr, spREAL*, spREAL*, spREAL*, spREAL* ); -extern void spSolveTransposed(MatrixPtr,spREAL*,spREAL*,spREAL*,spREAL*); - +#if spCOMPLEX +spcEXTERN void spDeterminant( spMatrix, int*, spREAL*, spREAL* ); +#else /* NOT spCOMPLEX */ +spcEXTERN void spDeterminant( spMatrix, int*, spREAL* ); +#endif /* NOT spCOMPLEX */ +#if spCOMPLEX && spSEPARATED_COMPLEX_VECTORS +spcEXTERN int spFileVector( spMatrix, char* , + spREAL[], spREAL[]); +spcEXTERN void spMultiply( spMatrix, spREAL[], spREAL[], + spREAL[], spREAL[] ); +spcEXTERN void spMultTransposed( spMatrix, spREAL[], spREAL[], + spREAL[], spREAL[] ); +spcEXTERN void spSolve( spMatrix, spREAL[], spREAL[], spREAL[], + spREAL[] ); +spcEXTERN void spSolveTransposed( spMatrix, spREAL[], spREAL[], + spREAL[], spREAL[] ); +#else /* NOT (spCOMPLEX && spSEPARATED_COMPLEX_VECTORS) */ +spcEXTERN int spFileVector( spMatrix, char* , spREAL[] ); +spcEXTERN void spMultiply( spMatrix, spREAL[], spREAL[] ); +spcEXTERN void spMultTransposed( spMatrix, + spREAL[], spREAL[] ); +spcEXTERN void spSolve( spMatrix, spREAL[], spREAL[] ); +spcEXTERN void spSolveTransposed( spMatrix, + spREAL[], spREAL[] ); +#endif /* NOT (spCOMPLEX && spSEPARATED_COMPLEX_VECTORS) */ #endif /* spOKAY */ +//spcEXTERN void spConstMult(spMatrix, double); diff --git a/src/maths/sparse/Makefile.am b/src/maths/sparse/Makefile.am index ccbdcf969..e44201cb5 100644 --- a/src/maths/sparse/Makefile.am +++ b/src/maths/sparse/Makefile.am @@ -3,16 +3,16 @@ noinst_LTLIBRARIES = libsparse.la libsparse_la_SOURCES = \ - spalloc.c \ - spbuild.c \ - spconfig.h \ - spdefs.h \ + spAllocate.c \ + spBuild.c \ + spConfig.h \ + spDefs.h \ spextra.c \ - spfactor.c \ - spoutput.c \ - spsmp.c \ - spsolve.c \ - sputils.c + spFactor.c \ + spOutput.c \ + spSMP.c \ + spSolve.c \ + spUtils.c diff --git a/src/maths/sparse/spAllocate.c b/src/maths/sparse/spAllocate.c new file mode 100644 index 000000000..edc3c0d1b --- /dev/null +++ b/src/maths/sparse/spAllocate.c @@ -0,0 +1,863 @@ +/* + * MATRIX ALLOCATION MODULE + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + */ +/*!\file + * This file contains functions for allocating and freeing matrices, configuring them, and for + * accessing global information about the matrix (size, error status, etc.). + * + * Objects that begin with the \a spc prefix are considered private + * and should not be used. + * + * \author + * Kenneth S. Kundert + */ +/* >>> User accessible functions contained in this file: + * spCreate + * spDestroy + * spErrorState + * spWhereSingular + * spGetSize + * spSetReal + * spSetComplex + * spFillinCount + * spElementCount + * + * >>> Other functions contained in this file: + * spcGetElement + * InitializeElementBlocks + * spcGetFillin + * RecordAllocation + * AllocateBlockOfAllocationList + * EnlargeMatrix + * ExpandTranslationArrays + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985-2003 by Kenneth S. Kundert + */ + + + +/* + * 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 +#include "spConfig.h" +#include "ngspice/spmatrix.h" +#include "spDefs.h" + + + + + +/* + * Global strings + */ + +char spcMatrixIsNotValid[] = "Matrix passed to Sparse is not valid"; +char spcErrorsMustBeCleared[] = "Error not cleared"; +char spcMatrixMustBeFactored[] = "Matrix must be factored"; +char spcMatrixMustNotBeFactored[] = "Matrix must not be factored"; + + + + +/* + * Function declarations + */ + +//static spError ReserveElements( MatrixPtr, int ); +static void InitializeElementBlocks( MatrixPtr, int, int ); +static void RecordAllocation( MatrixPtr, void* ); +static void AllocateBlockOfAllocationList( MatrixPtr ); + + + +/*! + * Allocates and initializes the data structures associated with a matrix. + * + * \return + * A pointer to the matrix is returned cast into \a spMatrix (typically a + * pointer to a void). This pointer is then passed and used by the other + * matrix routines to refer to a particular matrix. If an error occurs, + * the \a NULL pointer is returned. + * + * \param Size + * Size of matrix or estimate of size of matrix if matrix is \a EXPANDABLE. + * \param Complex + * Type of matrix. If \a Complex is 0 then the matrix is real, otherwise + * the matrix will be complex. Note that if the routines are not set up + * to handle the type of matrix requested, then an \a spPANIC error will occur. + * Further note that if a matrix will be both real and complex, it must + * be specified here as being complex. + * \param pError + * Returns error flag, needed because function \a spErrorState() will + * not work correctly if \a spCreate() returns \a NULL. Possible errors + * include \a spNO_MEMORY and \a spPANIC. + */ +/* >>> Local variables: + * AllocatedSize (int) + * The size of the matrix being allocated. + * Matrix (MatrixPtr) + * A pointer to the matrix frame being created. + */ + +spMatrix +spCreate( + int Size, + int Complex, + int *pError +) +{ +register unsigned SizePlusOne; +register MatrixPtr Matrix; +register int I; +int AllocatedSize; + +/* Begin `spCreate'. */ +/* Clear error flag. */ + *pError = spOKAY; + +/* Test for valid size. */ + vASSERT( (Size >= 0) AND (Size != 0 OR EXPANDABLE), "Invalid size" ); + +/* Test for valid type. */ +#if NOT spCOMPLEX + ASSERT( NOT Complex ); +#endif +#if NOT REAL + ASSERT( Complex ); +#endif + +/* Create Matrix. */ + AllocatedSize = MAX( Size, MINIMUM_ALLOCATED_SIZE ); + SizePlusOne = (unsigned)(AllocatedSize + 1); + + if ((Matrix = ALLOC(struct MatrixFrame, 1)) == NULL) + { *pError = spNO_MEMORY; + return NULL; + } + +/* Initialize matrix */ + Matrix->ID = SPARSE_ID; + Matrix->Complex = Complex; + Matrix->PreviousMatrixWasComplex = Complex; + Matrix->Factored = NO; + Matrix->Elements = 0; + Matrix->Error = *pError; + Matrix->Fillins = 0; + Matrix->Reordered = NO; + Matrix->NeedsOrdering = YES; + Matrix->NumberOfInterchangesIsOdd = NO; + Matrix->Partitioned = NO; + Matrix->RowsLinked = NO; + Matrix->InternalVectorsAllocated = NO; + Matrix->SingularCol = 0; + Matrix->SingularRow = 0; + Matrix->Size = Size; + Matrix->AllocatedSize = AllocatedSize; + Matrix->ExtSize = Size; + Matrix->AllocatedExtSize = AllocatedSize; + Matrix->CurrentSize = 0; + Matrix->ExtToIntColMap = NULL; + Matrix->ExtToIntRowMap = NULL; + Matrix->IntToExtColMap = NULL; + Matrix->IntToExtRowMap = NULL; + Matrix->MarkowitzRow = NULL; + Matrix->MarkowitzCol = NULL; + Matrix->MarkowitzProd = NULL; + Matrix->DoCmplxDirect = NULL; + Matrix->DoRealDirect = NULL; + Matrix->Intermediate = NULL; + Matrix->RelThreshold = DEFAULT_THRESHOLD; + Matrix->AbsThreshold = 0.0; + + Matrix->TopOfAllocationList = NULL; + Matrix->RecordsRemaining = 0; + Matrix->ElementsRemaining = 0; + Matrix->FillinsRemaining = 0; + + RecordAllocation( Matrix, (void *)Matrix ); + if (Matrix->Error == spNO_MEMORY) goto MemoryError; + +/* Take out the trash. */ + Matrix->TrashCan.Real = 0.0; +#if spCOMPLEX + Matrix->TrashCan.Imag = 0.0; +#endif + Matrix->TrashCan.Row = 0; + Matrix->TrashCan.Col = 0; + Matrix->TrashCan.NextInRow = NULL; + Matrix->TrashCan.NextInCol = NULL; +#if INITIALIZE + Matrix->TrashCan.pInitInfo = NULL; +#endif + +/* Allocate space in memory for Diag pointer vector. */ + CALLOC( Matrix->Diag, ElementPtr, SizePlusOne); + if (Matrix->Diag == NULL) + goto MemoryError; + +/* Allocate space in memory for FirstInCol pointer vector. */ + CALLOC( Matrix->FirstInCol, ElementPtr, SizePlusOne); + if (Matrix->FirstInCol == NULL) + goto MemoryError; + +/* Allocate space in memory for FirstInRow pointer vector. */ + CALLOC( Matrix->FirstInRow, ElementPtr, SizePlusOne); + if (Matrix->FirstInRow == NULL) + goto MemoryError; + +/* Allocate space in memory for IntToExtColMap vector. */ + if (( Matrix->IntToExtColMap = ALLOC(int, SizePlusOne)) == NULL) + goto MemoryError; + +/* Allocate space in memory for IntToExtRowMap vector. */ + if (( Matrix->IntToExtRowMap = ALLOC(int, SizePlusOne)) == NULL) + goto MemoryError; + +/* Initialize MapIntToExt vectors. */ + for (I = 1; I <= AllocatedSize; I++) + { Matrix->IntToExtRowMap[I] = I; + Matrix->IntToExtColMap[I] = I; + } + +#if TRANSLATE +/* Allocate space in memory for ExtToIntColMap vector. */ + if (( Matrix->ExtToIntColMap = ALLOC(int, SizePlusOne)) == NULL) + goto MemoryError; + +/* Allocate space in memory for ExtToIntRowMap vector. */ + if (( Matrix->ExtToIntRowMap = ALLOC(int, SizePlusOne)) == NULL) + goto MemoryError; + +/* Initialize MapExtToInt vectors. */ + for (I = 1; I <= AllocatedSize; I++) + { Matrix->ExtToIntColMap[I] = -1; + Matrix->ExtToIntRowMap[I] = -1; + } + Matrix->ExtToIntColMap[0] = 0; + Matrix->ExtToIntRowMap[0] = 0; +#endif + +/* Allocate space for fill-ins and initial set of elements. */ + InitializeElementBlocks( Matrix, SPACE_FOR_ELEMENTS*AllocatedSize, + SPACE_FOR_FILL_INS*AllocatedSize ); + if (Matrix->Error == spNO_MEMORY) + goto MemoryError; + + return (char *)Matrix; + +MemoryError: + +/* Deallocate matrix and return no pointer to matrix if there is not enough + memory. */ + *pError = spNO_MEMORY; + spDestroy( (char *)Matrix); + return NULL; +} + + + + + + + + + +/* + * ELEMENT ALLOCATION + * + * This routine allocates space for matrix elements. It requests large blocks + * of storage from the system and doles out individual elements as required. + * This technique, as opposed to allocating elements individually, tends to + * speed the allocation process. + * + * >>> Returned: + * A pointer to an element. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * + * >>> Local variables: + * pElement (ElementPtr) + * A pointer to the first element in the group of elements being allocated. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +ElementPtr +spcGetElement( MatrixPtr Matrix ) +{ +ElementPtr pElement; + +/* Begin `spcGetElement'. */ + +/* Allocate block of MatrixElements if necessary. */ + if (Matrix->ElementsRemaining == 0) + { pElement = ALLOC(struct MatrixElement, ELEMENTS_PER_ALLOCATION); + RecordAllocation( Matrix, (void *)pElement ); + if (Matrix->Error == spNO_MEMORY) return NULL; + Matrix->ElementsRemaining = ELEMENTS_PER_ALLOCATION; + Matrix->NextAvailElement = pElement; + } + +/* Update Element counter and return pointer to Element. */ + Matrix->ElementsRemaining--; + return Matrix->NextAvailElement++; +} + + + + + + + + +/* + * ELEMENT ALLOCATION INITIALIZATION + * + * This routine allocates space for matrix fill-ins and an initial set of + * elements. Besides being faster than allocating space for elements one + * at a time, it tends to keep the fill-ins physically close to the other + * matrix elements in the computer memory. This keeps virtual memory paging + * to a minimum. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * InitialNumberOfElements (int) + * This number is used as the size of the block of memory, in + * MatrixElements, reserved for elements. If more than this number of + * elements are generated, then more space is allocated later. + * NumberOfFillinsExpected (int) + * This number is used as the size of the block of memory, in + * MatrixElements, reserved for fill-ins. If more than this number of + * fill-ins are generated, then more space is allocated, but they may + * not be physically close in computer's memory. + * + * >>> Local variables: + * pElement (ElementPtr) + * A pointer to the first element in the group of elements being allocated. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static void +InitializeElementBlocks( + MatrixPtr Matrix, + int InitialNumberOfElements, + int NumberOfFillinsExpected +) +{ +ElementPtr pElement; + +/* Begin `InitializeElementBlocks'. */ + +/* Allocate block of MatrixElements for elements. */ + pElement = ALLOC(struct MatrixElement, InitialNumberOfElements); + RecordAllocation( Matrix, (void *)pElement ); + if (Matrix->Error == spNO_MEMORY) return; + Matrix->ElementsRemaining = InitialNumberOfElements; + Matrix->NextAvailElement = pElement; + +/* Allocate block of MatrixElements for fill-ins. */ + pElement = ALLOC(struct MatrixElement, NumberOfFillinsExpected); + RecordAllocation( Matrix, (void *)pElement ); + if (Matrix->Error == spNO_MEMORY) return; + Matrix->FillinsRemaining = NumberOfFillinsExpected; + Matrix->NextAvailFillin = pElement; + +/* Allocate a fill-in list structure. */ + Matrix->FirstFillinListNode = ALLOC(struct FillinListNodeStruct,1); + RecordAllocation( Matrix, (void *)Matrix->FirstFillinListNode ); + if (Matrix->Error == spNO_MEMORY) return; + Matrix->LastFillinListNode = Matrix->FirstFillinListNode; + + Matrix->FirstFillinListNode->pFillinList = pElement; + Matrix->FirstFillinListNode->NumberOfFillinsInList =NumberOfFillinsExpected; + Matrix->FirstFillinListNode->Next = NULL; + + return; +} + + + + + + + + + + +/* + * FILL-IN ALLOCATION + * + * This routine allocates space for matrix fill-ins. It requests large blocks + * of storage from the system and doles out individual elements as required. + * This technique, as opposed to allocating elements individually, tends to + * speed the allocation process. + * + * >>> Returned: + * A pointer to the fill-in. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +ElementPtr +spcGetFillin( MatrixPtr Matrix ) +{ +#if STRIP OR LINT +struct FillinListNodeStruct *pListNode; +ElementPtr pFillins; +#endif + +/* Begin `spcGetFillin'. */ + +#if NOT STRIP OR LINT + if (Matrix->FillinsRemaining == 0) + return spcGetElement( Matrix ); +#endif +#if STRIP OR LINT + + if (Matrix->FillinsRemaining == 0) + { pListNode = Matrix->LastFillinListNode; + +/* First see if there are any stripped fill-ins left. */ + if (pListNode->Next != NULL) + { Matrix->LastFillinListNode = pListNode = pListNode->Next; + Matrix->FillinsRemaining = pListNode->NumberOfFillinsInList; + Matrix->NextAvailFillin = pListNode->pFillinList; + } + else + { +/* Allocate block of fill-ins. */ + pFillins = ALLOC(struct MatrixElement, ELEMENTS_PER_ALLOCATION); + RecordAllocation( Matrix, (void *)pFillins ); + if (Matrix->Error == spNO_MEMORY) return NULL; + Matrix->FillinsRemaining = ELEMENTS_PER_ALLOCATION; + Matrix->NextAvailFillin = pFillins; + +/* Allocate a fill-in list structure. */ + pListNode->Next = ALLOC(struct FillinListNodeStruct,1); + RecordAllocation( Matrix, (void *)pListNode->Next ); + if (Matrix->Error == spNO_MEMORY) return NULL; + Matrix->LastFillinListNode = pListNode = pListNode->Next; + + pListNode->pFillinList = pFillins; + pListNode->NumberOfFillinsInList = ELEMENTS_PER_ALLOCATION; + pListNode->Next = NULL; + } + } +#endif + +/* Update Fill-in counter and return pointer to Fill-in. */ + Matrix->FillinsRemaining--; + return Matrix->NextAvailFillin++; +} + + + + + + + + + +/* + * RECORD A MEMORY ALLOCATION + * + * This routine is used to record all memory allocations so that the memory + * can be freed later. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * AllocatedPtr (void *) + * The pointer returned by malloc or calloc. These pointers are saved in + * a list so that they can be easily freed. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static void +RecordAllocation( + MatrixPtr Matrix, + void *AllocatedPtr +) +{ +/* Begin `RecordAllocation'. */ +/* + * If Allocated pointer is NULL, assume that malloc returned a NULL pointer, + * which indicates a spNO_MEMORY error. + */ + if (AllocatedPtr == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + +/* Allocate block of MatrixElements if necessary. */ + if (Matrix->RecordsRemaining == 0) + { AllocateBlockOfAllocationList( Matrix ); + if (Matrix->Error == spNO_MEMORY) + { FREE(AllocatedPtr); + return; + } + } + +/* Add Allocated pointer to Allocation List. */ + (++Matrix->TopOfAllocationList)->AllocatedPtr = AllocatedPtr; + Matrix->RecordsRemaining--; + return; + +} + + + + + + + + +/* + * ADD A BLOCK OF SLOTS TO ALLOCATION LIST + * + * This routine increases the size of the allocation list. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * + * >>> Local variables: + * ListPtr (AllocationListPtr) + * Pointer to the list that contains the pointers to segments of memory + * that were allocated by the operating system for the current matrix. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static void +AllocateBlockOfAllocationList( MatrixPtr Matrix ) +{ +register int I; +register AllocationListPtr ListPtr; + +/* Begin `AllocateBlockOfAllocationList'. */ +/* Allocate block of records for allocation list. */ + ListPtr = ALLOC(struct AllocationRecord, (ELEMENTS_PER_ALLOCATION+1)); + if (ListPtr == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + +/* String entries of allocation list into singly linked list. List is linked + such that any record points to the one before it. */ + + ListPtr->NextRecord = Matrix->TopOfAllocationList; + Matrix->TopOfAllocationList = ListPtr; + ListPtr += ELEMENTS_PER_ALLOCATION; + for (I = ELEMENTS_PER_ALLOCATION; I > 0; I--) + { ListPtr->NextRecord = ListPtr - 1; + ListPtr--; + } + +/* Record allocation of space for allocation list on allocation list. */ + Matrix->TopOfAllocationList->AllocatedPtr = (void *)ListPtr; + Matrix->RecordsRemaining = ELEMENTS_PER_ALLOCATION; + + return; +} + + + + + + + + +/*! + * Destroys a matrix and frees all memory associated with it. + * + * \param eMatrix + * Pointer to the matrix frame which is to be destroyed. + */ +/* >>> Local variables: + * ListPtr (AllocationListPtr) + * Pointer into the linked list of pointers to allocated data structures. + * Points to pointer to structure to be freed. + * NextListPtr (AllocationListPtr) + * Pointer into the linked list of pointers to allocated data structures. + * Points to the next pointer to structure to be freed. This is needed + * because the data structure to be freed could include the current node + * in the allocation list. + */ + +void +spDestroy( spMatrix eMatrix ) +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register AllocationListPtr ListPtr, NextListPtr; + +/* Begin `spDestroy'. */ + ASSERT_IS_SPARSE( Matrix ); + +/* Deallocate the vectors that are located in the matrix frame. */ + FREE( Matrix->IntToExtColMap ); + FREE( Matrix->IntToExtRowMap ); + FREE( Matrix->ExtToIntColMap ); + FREE( Matrix->ExtToIntRowMap ); + FREE( Matrix->Diag ); + FREE( Matrix->FirstInRow ); + FREE( Matrix->FirstInCol ); + FREE( Matrix->MarkowitzRow ); + FREE( Matrix->MarkowitzCol ); + FREE( Matrix->MarkowitzProd ); + FREE( Matrix->DoCmplxDirect ); + FREE( Matrix->DoRealDirect ); + FREE( Matrix->Intermediate ); + +/* Sequentially step through the list of allocated pointers freeing pointers + * along the way. */ + ListPtr = Matrix->TopOfAllocationList; + while (ListPtr != NULL) + { NextListPtr = ListPtr->NextRecord; + free( ListPtr->AllocatedPtr ); + ListPtr = NextListPtr; + } + return; +} + + + + + + + +/*! + * This function returns the error status of the given matrix. + * + * \return + * The error status of the given matrix. + * + * \param eMatrix + * The pointer to the matrix for which the error status is desired. + */ + +int +spErrorState( spMatrix eMatrix ) +{ +/* Begin `spErrorState'. */ + + if (eMatrix != NULL) + { ASSERT_IS_SPARSE( (MatrixPtr)eMatrix ); + return ((MatrixPtr)eMatrix)->Error; + } + else return spNO_MEMORY; /* This error may actually be spPANIC, + * no way to tell. */ +} + + + + + + + + + +/*! + * This function returns the row and column number where the matrix was + * detected as singular (if pivoting was allowed on the last factorization) + * or where a zero was detected on the diagonal (if pivoting was not + * allowed on the last factorization). Pivoting is performed only in + * spOrderAndFactor(). + * + * \param eMatrix + * The matrix for which the error status is desired. + * \param pRow + * The row number. + * \param pCol + * The column number. + */ + +void +spWhereSingular( + spMatrix eMatrix, + int *pRow, + int *pCol +) +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; + +/* Begin `spWhereSingular'. */ + ASSERT_IS_SPARSE( Matrix ); + + if (Matrix->Error == spSINGULAR OR Matrix->Error == spZERO_DIAG) + { *pRow = Matrix->SingularRow; + *pCol = Matrix->SingularCol; + } + else *pRow = *pCol = 0; + return; +} + + + + + + +/*! + * Returns the size of the matrix. Either the internal or external size of + * the matrix is returned. + * + * \param eMatrix + * Pointer to matrix. + * \param External + * If \a External is set true, the external size , i.e., the value of the + * largest external row or column number encountered is returned. + * Otherwise the true size of the matrix is returned. These two sizes + * may differ if the \a TRANSLATE option is set true. + */ + +int +spGetSize( + spMatrix eMatrix, + int External +) +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; + +/* Begin `spGetSize'. */ + ASSERT_IS_SPARSE( Matrix ); + +#if TRANSLATE + if (External) + return Matrix->ExtSize; + else + return Matrix->Size; +#else + return Matrix->Size; +#endif +} + + + + + + + + +/*! + * Forces matrix to be real. + * + * \param eMatrix + * Pointer to matrix. + */ + +void +spSetReal( spMatrix eMatrix ) +{ +/* Begin `spSetReal'. */ + + ASSERT_IS_SPARSE( (MatrixPtr)eMatrix ); + vASSERT( REAL, "Sparse not compiled to handle real matrices" ); + ((MatrixPtr)eMatrix)->Complex = NO; + return; +} + + +/*! + * Forces matrix to be complex. + * + * \param eMatrix + * Pointer to matrix. + */ + +void +spSetComplex( spMatrix eMatrix ) +{ +/* Begin `spSetComplex'. */ + + ASSERT_IS_SPARSE( (MatrixPtr)eMatrix ); + vASSERT( spCOMPLEX, "Sparse not compiled to handle complex matrices" ); + ((MatrixPtr)eMatrix)->Complex = YES; + return; +} + + + + + + + + + +/*! + * This function returns the number of fill-ins that currently exists in a matrix. + * + * \param eMatrix + * Pointer to matrix. + */ + +int +spFillinCount( spMatrix eMatrix ) +{ +/* Begin `spFillinCount'. */ + + ASSERT_IS_SPARSE( (MatrixPtr)eMatrix ); + return ((MatrixPtr)eMatrix)->Fillins; +} + + +/*! + * This function returns the total number of elements (including fill-ins) that currently exists in a matrix. + * + * \param eMatrix + * Pointer to matrix. + */ + +/* FIXME: Seems no different size entries available anymore */ + +int +spElementCount( spMatrix eMatrix ) +{ +/* Begin `spElementCount'. */ + + ASSERT_IS_SPARSE( (MatrixPtr)eMatrix ); + return ((MatrixPtr)eMatrix)->Elements; +} + +int +spOriginalCount( spMatrix eMatrix ) +{ + /* Begin `spOriginalCount'. */ + + ASSERT_IS_SPARSE( (MatrixPtr)eMatrix ); + return ((MatrixPtr)eMatrix)->Elements; +} + diff --git a/src/maths/sparse/spBuild.c b/src/maths/sparse/spBuild.c new file mode 100644 index 000000000..415626417 --- /dev/null +++ b/src/maths/sparse/spBuild.c @@ -0,0 +1,1284 @@ +/* + * MATRIX BUILD MODULE + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + */ +/*!\file + * This file contains the routines associated with clearing, loading and + * preprocessing the matrix. + * + * Objects that begin with the \a spc prefix are considered private + * and should not be used. + * + * \author + * Kenneth S. Kundert + */ +/* >>> User accessible functions contained in this file: + * spClear + * spFindElement + * spGetElement + * spGetAdmittance + * spGetQuad + * spGetOnes + * spInstallInitInfo + * spGetInitInfo + * spInitialize + * + * >>> Other functions contained in this file: + * Translate + * spcFindDiag + * spcCreateElement + * spcLinkRows + * EnlargeMatrix + * ExpandTranslationArrays + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985-2003 by Kenneth S. Kundert + */ + + + + +/* + * 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 +#include "spConfig.h" +#include "ngspice/spmatrix.h" +#include "spDefs.h" + + + + + +/* + * Function declarations + */ + +#if TRANSLATE +static void Translate( MatrixPtr, int*, int* ); +static void ExpandTranslationArrays( MatrixPtr, int ); +#endif +static void EnlargeMatrix( MatrixPtr, int ); + + + + + + +/*! + * Sets every element of the matrix to zero and clears the error flag. + * + * \param eMatrix + * Pointer to matrix that is to be cleared. + */ +/* >>> Local variables: + * pElement (ElementPtr) + * A pointer to the element being cleared. + */ + +void +spClear( spMatrix eMatrix ) +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register int I; + +/* Begin `spClear'. */ + ASSERT_IS_SPARSE( Matrix ); + +/* Clear matrix. */ +#if spCOMPLEX + if (Matrix->PreviousMatrixWasComplex OR Matrix->Complex) + { for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { pElement->Real = 0.0; + pElement->Imag = 0.0; + pElement = pElement->NextInCol; + } + } + } + else +#endif + { for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { pElement->Real = 0.0; + pElement = pElement->NextInCol; + } + } + } + +/* Empty the trash. */ + Matrix->TrashCan.Real = 0.0; +#if spCOMPLEX + Matrix->TrashCan.Imag = 0.0; +#endif + + Matrix->Error = spOKAY; + Matrix->Factored = NO; + Matrix->SingularCol = 0; + Matrix->SingularRow = 0; + Matrix->PreviousMatrixWasComplex = Matrix->Complex; + return; +} + + + + + + + + + + +/*! + * This routine is used to find an element given its indices. It will not + * create it if it does not exist. + * + * \return + * A pointer to the desired element, or \a NULL if it does not exist. + * + * \param eMatrix + * Pointer to matrix. + * \param Row + * Row index for element. + * \param Col + * Column index for element. + * + * \see spGetElement() + */ +/* >>> Local variables: + * pElement (ElementPtr) + * Pointer to an element in the matrix. + */ + +spElement * +spFindElement( + spMatrix eMatrix, + int Row, + int Col +) +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +int StartAt; +long int Min = LARGEST_LONG_INTEGER; +#define BorderRight 0 /* Start at left border, move right. */ +#define BorderDown 1 /* Start at top border, move down. */ +#define DiagRight 2 /* Start at diagonal, move right. */ +#define DiagDown 3 /* Start at diagonal, move down. */ + +/* Begin `spFindElement'. */ + if (Row == Col) return &Matrix->Diag[Row]->Real; + +/* Determine where to start the search. */ + if (Matrix->RowsLinked) + { if ((Col >= Row) AND Matrix->Diag[Row]) + { Min = Col - Row; + StartAt = DiagRight; + } + else + { Min = Col; + StartAt = BorderRight; + } + } + if ((Row >= Col) AND Matrix->Diag[Col]) + { if (Row - Col < Min) + StartAt = DiagDown; + } + else if (Row < Min) + StartAt = BorderDown; + +/* Search column for element. */ + if ((StartAt == BorderDown) OR (StartAt == DiagDown)) + { if (StartAt == BorderDown) + pElement = Matrix->FirstInCol[Col]; + else + pElement = Matrix->Diag[Col]; + + while ((pElement != NULL) AND (pElement->Row < Row)) + pElement = pElement->NextInCol; + if (pElement AND (pElement->Row == Row)) + return &pElement->Real; + else + return NULL; + } + +/* Search row for element. */ + if (StartAt == BorderRight) + pElement = Matrix->FirstInRow[Row]; + else + pElement = Matrix->Diag[Row]; + + while ((pElement != NULL) AND (pElement->Col < Col)) + pElement = pElement->NextInRow; + if (pElement AND (pElement->Col == Col)) + return &pElement->Real; + else + return NULL; +} + + + + + + + + + +/*! + * Finds element [Row,Col] and returns a pointer to it. If element is + * not found then it is created and spliced into matrix. This routine + * is only to be used after spCreate() and before spMNA_Preorder(), + * spFactor() or spOrderAndFactor(). Returns a pointer to the + * real portion of an \a spElement. This pointer is later used by + * \a spADD_xxx_ELEMENT to directly access element. + * + * \return + * Returns a pointer to the element. This pointer is then used to directly + * access the element during successive builds. + * + * \param eMatrix + * Pointer to the matrix that the element is to be added to. + * \param Row + * Row index for element. Must be in the range of [0..Size] unless + * the options \a EXPANDABLE or \a TRANSLATE are used. Elements placed in + * row zero are discarded. In no case may \a Row be less than zero. + * \param Col + * Column index for element. Must be in the range of [0..Size] unless + * the options \a EXPANDABLE or \a TRANSLATE are used. Elements placed in + * column zero are discarded. In no case may \a Col be less than zero. + + * \see spFindElement() + */ +/* >>> Local variables: + * pElement (RealNumber *) + * Pointer to the element. + * + * >>> Possible errors: + * spNO_MEMORY + * Error is not cleared in this routine. + */ + +spElement * +spGetElement( + spMatrix eMatrix, + int Row, + int Col +) +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +ElementPtr pElement; + +/* Begin `spGetElement'. */ + ASSERT_IS_SPARSE( Matrix ); + vASSERT( Row >= 0 AND Col >= 0, "Negative row or column number" ); + + if ((Row == 0) OR (Col == 0)) + return &Matrix->TrashCan.Real; + +#if NOT TRANSLATE + vASSERT( NOT Matrix->Reordered, + "Set TRANSLATE to add elements to a reordered matrix" ); +#endif + +#if TRANSLATE + Translate( Matrix, &Row, &Col ); + if (Matrix->Error == spNO_MEMORY) return NULL; +#endif + +#if NOT TRANSLATE +#if NOT EXPANDABLE + vASSERT( (Row <= Matrix->Size) AND (Col <= Matrix->Size), + "Row or column number too large" ); +#endif + +#if EXPANDABLE +/* Re-size Matrix if necessary. */ + if ((Row > Matrix->Size) OR (Col > Matrix->Size)) + EnlargeMatrix( Matrix, MAX(Row, Col) ); + if (Matrix->Error == spNO_MEMORY) return NULL; +#endif +#endif + + if ((Row != Col) OR ((pElement = Matrix->Diag[Row]) == NULL)) + { /* + * Element does not exist or does not reside along diagonal. Search + * for element and if it does not exist, create it. + */ + pElement = spcCreateElement( Matrix, Row, Col, + &(Matrix->FirstInRow[Row]), + &(Matrix->FirstInCol[Col]), NO ); + } +/* + * Cast pointer into a pointer to a RealNumber. This requires that Real + * be the first record in the MatrixElement structure. + */ + return &pElement->Real; +} + + + +/* + * FIND ELEMENT BY SEARCHING COLUMN + * + * Searches column starting at element specified at PtrAddr and finds element + * in Row. If Element does not exists, it is created. The pointer to the + * element is returned. + * + * >>> Returned: + * A pointer to the desired element: + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to Matrix. + * LastAddr (ElementPtr *) + * Address of pointer that initially points to the element in Col at which + * the search is started. The pointer in this location may be changed if + * a fill-in is required in and adjacent element. For this reason it is + * important that LastAddr be the address of a FirstInCol or a NextInCol + * rather than a temporary variable. + * Row (int) + * Row being searched for. + * Col (int) + * Column being searched. + * CreateIfMissing (int) + * Indicates what to do if element is not found, create one or return a + * NULL pointer. + * + * Local variables: + * pElement (ElementPtr) + * Pointer used to search through matrix. + */ + +ElementPtr +spcFindElementInCol(MatrixPtr Matrix, ElementPtr *LastAddr, + int Row, int Col, int CreateIfMissing) +{ + ElementPtr pElement; + + /* Begin `spcFindElementInCol'. */ + pElement = *LastAddr; + + /* Search for element. */ + while (pElement != NULL) + { + if (pElement->Row < Row) + { + /* Have not reached element yet. */ + LastAddr = &(pElement->NextInCol); + pElement = pElement->NextInCol; + } + else if (pElement->Row == Row) + { + /* Reached element. */ + return pElement; + } + else break; /* while loop */ + } + + /* Element does not exist and must be created. */ + if (CreateIfMissing) + return spcCreateElement( Matrix, Row, Col, LastAddr, NO, 0); + else + return NULL; +} + + +#if TRANSLATE + +/* + * TRANSLATE EXTERNAL INDICES TO INTERNAL + * + * Convert internal row and column numbers to internal row and column numbers. + * Also updates Ext/Int maps. + * + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * Row (int *) + * Upon entry Row is either a external row number of an external node + * number. Upon entry, the internal equivalent is supplied. + * Col (int *) + * Upon entry Column is either a external column number of an external node + * number. Upon entry, the internal equivalent is supplied. + * + * >>> Local variables: + * ExtCol (int) + * Temporary variable used to hold the external column or node number + * during the external to internal column number translation. + * ExtRow (int) + * Temporary variable used to hold the external row or node number during + * the external to internal row number translation. + * IntCol (int) + * Temporary variable used to hold the internal column or node number + * during the external to internal column number translation. + * IntRow (int) + * Temporary variable used to hold the internal row or node number during + * the external to internal row number translation. + */ + +static void +Translate( + MatrixPtr Matrix, + int *Row, + int *Col +) +{ +register int IntRow, IntCol, ExtRow, ExtCol; + +/* Begin `Translate'. */ + ExtRow = *Row; + ExtCol = *Col; + +/* Expand translation arrays if necessary. */ + if ((ExtRow > Matrix->AllocatedExtSize) OR + (ExtCol > Matrix->AllocatedExtSize)) + { + ExpandTranslationArrays( Matrix, MAX(ExtRow, ExtCol) ); + if (Matrix->Error == spNO_MEMORY) return; + } + +/* Set ExtSize if necessary. */ + if ((ExtRow > Matrix->ExtSize) OR (ExtCol > Matrix->ExtSize)) + Matrix->ExtSize = MAX(ExtRow, ExtCol); + +/* Translate external row or node number to internal row or node number. */ + if ((IntRow = Matrix->ExtToIntRowMap[ExtRow]) == -1) + { Matrix->ExtToIntRowMap[ExtRow] = ++Matrix->CurrentSize; + Matrix->ExtToIntColMap[ExtRow] = Matrix->CurrentSize; + IntRow = Matrix->CurrentSize; + +#if NOT EXPANDABLE + vASSERT( IntRow <= Matrix->Size, "Matrix size fixed" ); +#endif + +#if EXPANDABLE +/* Re-size Matrix if necessary. */ + if (IntRow > Matrix->Size) + EnlargeMatrix( Matrix, IntRow ); + if (Matrix->Error == spNO_MEMORY) return; +#endif + + Matrix->IntToExtRowMap[IntRow] = ExtRow; + Matrix->IntToExtColMap[IntRow] = ExtRow; + } + +/* Translate external column or node number to internal column or node number.*/ + if ((IntCol = Matrix->ExtToIntColMap[ExtCol]) == -1) + { Matrix->ExtToIntRowMap[ExtCol] = ++Matrix->CurrentSize; + Matrix->ExtToIntColMap[ExtCol] = Matrix->CurrentSize; + IntCol = Matrix->CurrentSize; + +#if NOT EXPANDABLE + vASSERT( IntCol <= Matrix->Size, "Matrix size fixed" ); +#endif + +#if EXPANDABLE +/* Re-size Matrix if necessary. */ + if (IntCol > Matrix->Size) + EnlargeMatrix( Matrix, IntCol ); + if (Matrix->Error == spNO_MEMORY) return; +#endif + + Matrix->IntToExtRowMap[IntCol] = ExtCol; + Matrix->IntToExtColMap[IntCol] = ExtCol; + } + + *Row = IntRow; + *Col = IntCol; + return; +} +#endif + + + + + + +#if QUAD_ELEMENT +/*! + * Performs same function as spGetElement() except rather than one + * element, all four matrix elements for a floating two terminal + * admittance component are added. This routine also works if component + * is grounded. Positive elements are placed at [Node1,Node2] and + * [Node2,Node1]. This routine is only to be used after spCreate() + * and before spMNA_Preorder(), spFactor() or spOrderAndFactor(). + * + * \return + * Error code. Possible errors include \a spNO_MEMORY. + * Error is not cleared in this routine. + * + * \param Matrix + * Pointer to the matrix that component is to be entered in. + * \param Node1 + * Row and column indices for elements. Must be in the range of [0..Size] + * unless the options \a EXPANDABLE or \a TRANSLATE are used. Node zero is the + * ground node. In no case may \a Node1 be less than zero. + * \param Node2 + * Row and column indices for elements. Must be in the range of [0..Size] + * unless the options \a EXPANDABLE or \a TRANSLATE are used. Node zero is the + * ground node. In no case may \a Node2 be less than zero. + * \param Template + * Collection of pointers to four elements that are later used to directly + * address elements. User must supply the template, this routine will + * fill it. + */ + +spError +spGetAdmittance( + spMatrix Matrix, + int Node1, + int Node2, + struct spTemplate *Template +) +{ + +/* Begin `spGetAdmittance'. */ + Template->Element1 = spGetElement(Matrix, Node1, Node1 ); + Template->Element2 = spGetElement(Matrix, Node2, Node2 ); + Template->Element3Negated = spGetElement( Matrix, Node2, Node1 ); + Template->Element4Negated = spGetElement( Matrix, Node1, Node2 ); + if + ( (Template->Element1 == NULL) + OR (Template->Element2 == NULL) + OR (Template->Element3Negated == NULL) + OR (Template->Element4Negated == NULL) + ) return spNO_MEMORY; + + if (Node1 == 0) + SWAP( RealNumber*, Template->Element1, Template->Element2 ); + + return spOKAY; +} +#endif /* QUAD_ELEMENT */ + + + + + + + + + +#if QUAD_ELEMENT +/*! + * Similar to spGetAdmittance(), except that spGetAdmittance() only + * handles 2-terminal components, whereas spGetQuad() handles simple + * 4-terminals as well. These 4-terminals are simply generalized + * 2-terminals with the option of having the sense terminals different + * from the source and sink terminals. spGetQuad() adds four + * elements to the matrix. Positive elements occur at [Row1,Col1] + * [Row2,Col2] while negative elements occur at [Row1,Col2] and [Row2,Col1]. + * The routine works fine if any of the rows and columns are zero. + * This routine is only to be used after spCreate() and before + * spMNA_Preorder(), spFactor() or spOrderAndFactor() + * unless \a TRANSLATE is set true. + * + * \return + * Error code. Possible errors include \a spNO_MEMORY. + * Error is not cleared in this routine. + * + * \param Matrix + * Pointer to the matrix that component is to be entered in. + * \param Row1 + * First row index for elements. Must be in the range of [0..Size] + * unless the options \a EXPANDABLE or \a TRANSLATE are used. Zero is the + * ground row. In no case may Row1 be less than zero. + * \param Row2 + * Second row index for elements. Must be in the range of [0..Size] + * unless the options \a EXPANDABLE or \a TRANSLATE are used. Zero is the + * ground row. In no case may Row2 be less than zero. + * \param Col1 + * First column index for elements. Must be in the range of [0..Size] + * unless the options \a EXPANDABLE or \a TRANSLATE are used. Zero is the + * ground column. In no case may Col1 be less than zero. + * \param Col2 + * Second column index for elements. Must be in the range of [0..Size] + * unless the options \a EXPANDABLE or \a TRANSLATE are used. Zero is the + * ground column. In no case may Col2 be less than zero. + * \param Template + * Collection of pointers to four elements that are later used to directly + * address elements. User must supply the template, this routine will + * fill it. + */ + +spError +spGetQuad( + spMatrix Matrix, + int Row1, + int Row2, + int Col1, + int Col2, + struct spTemplate *Template +) +{ +/* Begin `spGetQuad'. */ + Template->Element1 = spGetElement( Matrix, Row1, Col1); + Template->Element2 = spGetElement( Matrix, Row2, Col2 ); + Template->Element3Negated = spGetElement( Matrix, Row2, Col1 ); + Template->Element4Negated = spGetElement( Matrix, Row1, Col2 ); + if + ( (Template->Element1 == NULL) + OR (Template->Element2 == NULL) + OR (Template->Element3Negated == NULL) + OR (Template->Element4Negated == NULL) + ) return spNO_MEMORY; + + if (Template->Element1 == &((MatrixPtr)Matrix)->TrashCan.Real) + SWAP( RealNumber *, Template->Element1, Template->Element2 ); + + return spOKAY; +} +#endif /* QUAD_ELEMENT */ + + + + + + + + + +#if QUAD_ELEMENT +/*! + * Addition of four structural ones to matrix by index. + * Performs similar function to spGetQuad() except this routine is + * meant for components that do not have an admittance representation. + * + * The following stamp is used: \code + * Pos Neg Eqn + * Pos [ . . 1 ] + * Neg [ . . -1 ] + * Eqn [ 1 -1 . ] + * \endcode + * + * \return + * Error code. Possible errors include \a spNO_MEMORY. + * Error is not cleared in this routine. + * + * \param Matrix + * Pointer to the matrix that component is to be entered in. + * \param Pos + * See stamp above. Must be in the range of [0..Size] + * unless the options \a EXPANDABLE or \a TRANSLATE are used. Zero is the + * ground row. In no case may \a Pos be less than zero. + * \param Neg + * See stamp above. Must be in the range of [0..Size] + * unless the options \a EXPANDABLE or \a TRANSLATE are used. Zero is the + * ground row. In no case may \a Neg be less than zero. + * \param Eqn + * See stamp above. Must be in the range of [0..Size] + * unless the options \a EXPANDABLE or \a TRANSLATE are used. Zero is the + * ground row. In no case may \a Eqn be less than zero. + * \param Template + * Collection of pointers to four elements that are later used to directly + * address elements. User must supply the template, this routine will + * fill it. + */ + +spError +spGetOnes( + spMatrix Matrix, + int Pos, + int Neg, + int Eqn, + struct spTemplate *Template +) +{ +/* Begin `spGetOnes'. */ + Template->Element4Negated = spGetElement( Matrix, Neg, Eqn ); + Template->Element3Negated = spGetElement( Matrix, Eqn, Neg ); + Template->Element2 = spGetElement( Matrix, Pos, Eqn ); + Template->Element1 = spGetElement( Matrix, Eqn, Pos ); + if + ( (Template->Element1 == NULL) + OR (Template->Element2 == NULL) + OR (Template->Element3Negated == NULL) + OR (Template->Element4Negated == NULL) + ) return spNO_MEMORY; + + spADD_REAL_QUAD( *Template, 1.0 ); + return spOKAY; +} +#endif /* QUAD_ELEMENT */ + + + + + + + +/* + * FIND DIAGONAL + * + * This routine is used to find a diagonal element. It will not + * create it if it does not exist. + * + * >>> Returned: + * A pointer to the desired element, or NULL if it does not exist. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * Index (int) + * Row, Col index for diagonal element. + * + * >>> Local variables: + * pElement (ElementPtr) + * Pointer to an element in the matrix. + */ + +ElementPtr +spcFindDiag( + MatrixPtr Matrix, + register int Index +) +{ +register ElementPtr pElement; + +/* Begin `spcFindDiag'. */ + pElement = Matrix->FirstInCol[Index]; + +/* Search column for element. */ + while ((pElement != NULL) AND (pElement->Row < Index)) + pElement = pElement->NextInCol; + if (pElement AND (pElement->Row == Index)) + return pElement; + else + return NULL; +} + + + + + + + + +/* + * CREATE AND SPLICE ELEMENT INTO MATRIX + * + * This routine is used to create new matrix elements and splice them into the + * matrix. + * + * >>> Returned: + * A pointer to the element that was created is returned. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * Row (int) + * Row index for element. + * Col (int) + * Column index for element. + * ppToLeft (ElementPtr *) + * This contains the address of the pointer to an element to the left + * of the one being created. It is used to speed the search and if it + * is immediately to the left, it is updated with address of the + * created element. + * ppAbove (ElementPtr *) + * This contains the address of the pointer to an element above the + * one being created. It is used to speed the search and it if it + * is immediatley above, it is updated with address of the created + * element. + * Fillin (BOOLEAN) + * Flag that indicates if created element is to be a fill-in. + * + * >>> Local variables: + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * pCreatedElement (ElementPtr) + * Pointer to the desired element, the one that was just created. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +ElementPtr +spcCreateElement( + MatrixPtr Matrix, + int Row, + register int Col, + register ElementPtr *ppToLeft, + register ElementPtr *ppAbove, + BOOLEAN Fillin +) +{ +register ElementPtr pElement, pCreatedElement; + +/* Begin `spcCreateElement'. */ + +/* Find element immediately above the desired element. */ + pElement = *ppAbove; + while ((pElement != NULL) AND (pElement->Row < Row)) + { ppAbove = &pElement->NextInCol; + pElement = *ppAbove; + } + if ((pElement != NULL) AND (pElement->Row == Row)) + return pElement; + +/* The desired element does not exist, create it. */ + if (Fillin) + { pCreatedElement = spcGetFillin( Matrix ); + Matrix->Fillins++; + +/* Update Markowitz counts and products. */ + ++Matrix->MarkowitzRow[Row]; + spcMarkoProd( Matrix->MarkowitzProd[Row], + Matrix->MarkowitzRow[Row], + Matrix->MarkowitzCol[Row] ); + if ((Matrix->MarkowitzRow[Row] == 1) AND + (Matrix->MarkowitzCol[Row] != 0)) + { + Matrix->Singletons--; + } + ++Matrix->MarkowitzCol[Col]; + spcMarkoProd( Matrix->MarkowitzProd[Col], + Matrix->MarkowitzCol[Col], + Matrix->MarkowitzRow[Col] ); + if ((Matrix->MarkowitzRow[Col] != 0) AND + (Matrix->MarkowitzCol[Col] == 1)) + { + Matrix->Singletons--; + } + } + else + { pCreatedElement = spcGetElement( Matrix ); + Matrix->NeedsOrdering = YES; + } + if (pCreatedElement == NULL) return NULL; + Matrix->Elements++; + +/* Initialize Element. */ + pCreatedElement->Row = Row; + pCreatedElement->Col = Col; + pCreatedElement->Real = 0.0; +#if spCOMPLEX + pCreatedElement->Imag = 0.0; +#endif +#if INITIALIZE + pCreatedElement->pInitInfo = NULL; +#endif + +/* If element is on diagonal, store pointer in Diag. */ + if (Row == Col) Matrix->Diag[Row] = pCreatedElement; + +/* Splice element into column. */ + pCreatedElement->NextInCol = *ppAbove; + *ppAbove = pCreatedElement; + +/* Find Element immediately to the left of the fill-in. */ + if (Matrix->RowsLinked) + { pElement = *ppToLeft; + while (pElement != NULL) + { if (pElement->Col < Col) + { ppToLeft = &pElement->NextInRow; + pElement = *ppToLeft; + } + else break; /* while loop */ + } + +/* Splice element into row. */ + pCreatedElement->NextInRow = *ppToLeft; + *ppToLeft = pCreatedElement; + } + return pCreatedElement; +} + + + + + + + + +/* + * + * LINK ROWS + * + * This routine is used to generate the row links. The spGetElement() + * routines do not create row links, which are needed by the spFactor() + * routines. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * + * >>> Local variables: + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * FirstInRowEntry (ElementPtr *) + * A pointer into the FirstInRow array. Points to the FirstInRow entry + * currently being operated upon. + * FirstInRowArray (ArrayOfElementPtrs) + * A pointer to the FirstInRow array. Same as Matrix->FirstInRow but + * resides in a register and requires less indirection so is faster to + * use. + * Col (int) + * Column currently being operated upon. + */ + +void +spcLinkRows( MatrixPtr Matrix ) +{ +register ElementPtr pElement, *FirstInRowEntry; +register ArrayOfElementPtrs FirstInRowArray; +register int Col; + +/* Begin `spcLinkRows'. */ + FirstInRowArray = Matrix->FirstInRow; + for (Col = Matrix->Size; Col >= 1; Col--) + FirstInRowArray[Col] = NULL; + + for (Col = Matrix->Size; Col >= 1; Col--) + { +/* Generate row links for the elements in the Col'th column. */ + pElement = Matrix->FirstInCol[Col]; + + while (pElement != NULL) + { pElement->Col = Col; + FirstInRowEntry = &FirstInRowArray[pElement->Row]; + pElement->NextInRow = *FirstInRowEntry; + *FirstInRowEntry = pElement; + pElement = pElement->NextInCol; + } + } + Matrix->RowsLinked = YES; + return; +} + + + + + + + + +/* + * ENLARGE MATRIX + * + * Increases the size of the matrix. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * NewSize (int) + * The new size of the matrix. + * + * >>> Local variables: + * OldAllocatedSize (int) + * The allocated size of the matrix before it is expanded. + */ + +static void +EnlargeMatrix( + MatrixPtr Matrix, + register int NewSize +) +{ +register int I, OldAllocatedSize = Matrix->AllocatedSize; + +/* Begin `EnlargeMatrix'. */ + Matrix->Size = NewSize; + + if (NewSize <= OldAllocatedSize) + return; + +/* Expand the matrix frame. */ + NewSize = MAX( NewSize, (int)(EXPANSION_FACTOR * OldAllocatedSize) ); + Matrix->AllocatedSize = NewSize; + + if (( REALLOC(Matrix->IntToExtColMap, int, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->IntToExtRowMap, int, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->Diag, ElementPtr, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->FirstInCol, ElementPtr, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->FirstInRow, ElementPtr, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + +/* + * Destroy the Markowitz and Intermediate vectors, they will be recreated + * in spOrderAndFactor(). + */ + FREE( Matrix->MarkowitzRow ); + FREE( Matrix->MarkowitzCol ); + FREE( Matrix->MarkowitzProd ); + FREE( Matrix->DoRealDirect ); + FREE( Matrix->DoCmplxDirect ); + FREE( Matrix->Intermediate ); + Matrix->InternalVectorsAllocated = NO; + +/* Initialize the new portion of the vectors. */ + for (I = OldAllocatedSize+1; I <= NewSize; I++) + { Matrix->IntToExtColMap[I] = I; + Matrix->IntToExtRowMap[I] = I; + Matrix->Diag[I] = NULL; + Matrix->FirstInRow[I] = NULL; + Matrix->FirstInCol[I] = NULL; + } + + return; +} + + + + + + + + +#if TRANSLATE + +/* + * EXPAND TRANSLATION ARRAYS + * + * Increases the size arrays that are used to translate external to internal + * row and column numbers. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * NewSize (int) + * The new size of the translation arrays. + * + * >>> Local variables: + * OldAllocatedSize (int) + * The allocated size of the translation arrays before being expanded. + */ + +static void +ExpandTranslationArrays( + MatrixPtr Matrix, + register int NewSize +) +{ +register int I, OldAllocatedSize = Matrix->AllocatedExtSize; + +/* Begin `ExpandTranslationArrays'. */ + Matrix->ExtSize = NewSize; + + if (NewSize <= OldAllocatedSize) + return; + +/* Expand the translation arrays ExtToIntRowMap and ExtToIntColMap. */ + NewSize = MAX( NewSize, (int)(EXPANSION_FACTOR * OldAllocatedSize) ); + Matrix->AllocatedExtSize = NewSize; + + if (( REALLOC(Matrix->ExtToIntRowMap, int, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->ExtToIntColMap, int, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + +/* Initialize the new portion of the vectors. */ + for (I = OldAllocatedSize+1; I <= NewSize; I++) + { Matrix->ExtToIntRowMap[I] = -1; + Matrix->ExtToIntColMap[I] = -1; + } + + return; +} +#endif + + + + + + + + + +#if INITIALIZE +/*! + * Initialize the matrix. + * + * With the \a INITIALIZE compiler option (see spConfig.h) set true, + * Sparse allows the user to keep initialization information with each + * structurally nonzero matrix element. Each element has a pointer + * that is set and used by the user. The user can set this pointer + * using spInstallInitInfo() and may be read using spGetInitInfo(). Both + * may be used only after the element exists. The function + * spInitialize() is a user customizable way to initialize the matrix. + * Passed to this routine is a function pointer. spInitialize() sweeps + * through every element in the matrix and checks the \a pInitInfo + * pointer (the user supplied pointer). If the \a pInitInfo is \a NULL, + * which is true unless the user changes it (almost always true for + * fill-ins), then the element is zeroed. Otherwise, the function + * pointer is called and passed the \a pInitInfo pointer as well as the + * element pointer and the external row and column numbers. If the + * user sets the value of each element, then spInitialize() replaces + * spClear(). + * + * The user function is expected to return a nonzero integer if there + * is a fatal error and zero otherwise. Upon encountering a nonzero + * return code, spInitialize() terminates, sets the error state of + * the matrix to be \a spMANGLED, and returns the error code. + * + * \return + * Returns the return value of the \a pInit() function. + * \param eMatrix + * Pointer to matrix. + * \param pInit + * Pointer to a function that initializes an element. + + * \see spClear() + */ + +int +spInitialize( + spMatrix eMatrix, + int (*pInit)( + spElement *pElement, + spGenericPtr pInitInfo, + int Row, + int Col + ) +) +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +int J, Error, Col; + +/* Begin `spInitialize'. */ + ASSERT_IS_SPARSE( Matrix ); + +#if spCOMPLEX +/* Clear imaginary part of matrix if matrix is real but was complex. */ + if (Matrix->PreviousMatrixWasComplex AND NOT Matrix->Complex) + { for (J = Matrix->Size; J > 0; J--) + { pElement = Matrix->FirstInCol[J]; + while (pElement != NULL) + { pElement->Imag = 0.0; + pElement = pElement->NextInCol; + } + } + } +#endif /* spCOMPLEX */ + +/* Initialize the matrix. */ + for (J = Matrix->Size; J > 0; J--) + { pElement = Matrix->FirstInCol[J]; + Col = Matrix->IntToExtColMap[J]; + while (pElement != NULL) + { if (pElement->pInitInfo == NULL) + { pElement->Real = 0.0; +# if spCOMPLEX + pElement->Imag = 0.0; +# endif + } + else + { Error = (*pInit)((RealNumber *)pElement, pElement->pInitInfo, + Matrix->IntToExtRowMap[pElement->Row], Col); + if (Error) + { Matrix->Error = spMANGLED; + return Error; + } + + } + pElement = pElement->NextInCol; + } + } + +/* Empty the trash. */ + Matrix->TrashCan.Real = 0.0; +#if spCOMPLEX + Matrix->TrashCan.Imag = 0.0; +#endif + + Matrix->Error = spOKAY; + Matrix->Factored = NO; + Matrix->SingularCol = 0; + Matrix->SingularRow = 0; + Matrix->PreviousMatrixWasComplex = Matrix->Complex; + return 0; +} + + + + +/*! + * This function installs a pointer to a data structure that is used + * to contain initialization information to a matrix element. It is + * is then used by spInitialize() to initialize the matrix. + * + * \param pElement + * Pointer to matrix element. + * \param pInitInfo + * Pointer to the data structure that will contain initialiation + * information. + * \see spInitialize() + */ + +void +spInstallInitInfo( + spElement *pElement, + spGenericPtr pInitInfo +) +{ +/* Begin `spInstallInitInfo'. */ + vASSERT( pElement != NULL, "Invalid element pointer" ); + + ((ElementPtr)pElement)->pInitInfo = pInitInfo; +} + + +/*! + * This function returns a pointer to a data structure that is used + * to contain initialization information to a matrix element. + * + * \return + * The pointer to the initialiation information data structure + * that is associated with a particular matrix element. + * + * \param pElement + * Pointer to the matrix element. + * + * \see spInitialize() + */ +spGenericPtr +spGetInitInfo( + spElement *pElement +) +{ +/* Begin `spGetInitInfo'. */ + vASSERT( pElement != NULL, "Invalid element pointer" ); + + return (spGenericPtr)((ElementPtr)pElement)->pInitInfo; +} +#endif /* INITIALIZE */ diff --git a/src/maths/sparse/spConfig.h b/src/maths/sparse/spConfig.h new file mode 100644 index 000000000..86a5ed2fa --- /dev/null +++ b/src/maths/sparse/spConfig.h @@ -0,0 +1,572 @@ +/* CONFIGURATION MACRO DEFINITIONS for sparse matrix routines */ +/*! + * \file + * + * This file contains macros for the sparse matrix routines that are used + * to define the personality of the routines. The user is expected to + * modify this file to maximize the performance of the routines with + * his/her matrices. + * + * Macros are distinguished by using solely capital letters in their + * identifiers. This contrasts with C defined identifiers which are + * strictly lower case, and program variable and procedure names which use + * both upper and lower case. + * + * Objects that begin with the \a spc prefix are considered private + * and should not be used. + * + * \author + * Kenneth S. Kundert + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985-2003 by Kenneth S. Kundert + * + * $Date: 2003/06/30 19:41:29 $ + * $Revision: 1.5 $ + */ + + +#ifndef spCONFIG_DEFS +#define spCONFIG_DEFS + + + + +#ifdef spINSIDE_SPARSE +/* + * OPTIONS + * + * These are compiler options. Set each option to one to compile that + * section of the code. If a feature is not desired, set the macro + * to NO. + */ + +/* Begin options. */ + +/* Arithmetic Precision + * + * The precision of the arithmetic used by Sparse can be set by + * changing changing the spREAL macro. This macro is + * contained in the file spMatrix.h. It is strongly suggested to + * used double precision with circuit simulators. Note that + * because C always performs arithmetic operations in double + * precision, the only benefit to using single precision is that + * less storage is required. There is often a noticeable speed + * penalty when using single precision. Sparse internally refers + * to a spREAL as a RealNumber. + */ + +/*! + * This specifies that the routines are expected to handle real + * systems of equations. The routines can be compiled to handle + * both real and complex systems at the same time, but there is a + * slight speed and memory advantage if the routines are complied + * to handle only real systems of equations. + */ +#define REAL YES + +/*! + * Setting this compiler flag true (1) makes the matrix + * expandable before it has been factored. If the matrix is + * expandable, then if an element is added that would be + * considered out of bounds in the current matrix, the size of + * the matrix is increased to hold that element. As a result, + * the size of the matrix need not be known before the matrix is + * built. The matrix can be allocated with size zero and expanded. + */ +#define EXPANDABLE YES + +/*! + * This option allows the set of external row and column numbers + * to be non-packed. In other words, the row and column numbers + * do not have to be contiguous. The priced paid for this + * flexibility is that when \a TRANSLATE is set true, the time + * required to initially build the matrix will be greater because + * the external row and column number must be translated into + * internal equivalents. This translation brings about other + * benefits though. First, the spGetElement() and + * spGetAdmittance() routines may be used after the matrix has + * been factored. Further, elements, and even rows and columns, + * may be added to the matrix, and row and columns may be deleted + * from the matrix, after it has been factored. Note that when + * the set of row and column number is not a packed set, neither + * are the \a RHS and \a Solution vectors. Thus the size of these + * vectors must be at least as large as the external size, which + * is the value of the largest given row or column numbers. + */ +#define TRANSLATE YES + +/*! + * Causes the spInitialize(), spGetInitInfo(), and + * spInstallInitInfo() routines to be compiled. These routines + * allow the user to store and read one pointer in each nonzero + * element in the matrix. spInitialize() then calls a user + * specified function for each structural nonzero in the matrix, + * and includes this pointer as well as the external row and + * column numbers as arguments. This allows the user to write + * custom matrix initialization routines. + */ +#define INITIALIZE NO + +/*! + * Many matrices, and in particular node- and modified-node + * admittance matrices, tend to be nearly symmetric and nearly + * diagonally dominant. For these matrices, it is a good idea to + * select pivots from the diagonal. With this option enabled, + * this is exactly what happens, though if no satisfactory pivot + * can be found on the diagonal, an off-diagonal pivot will be + * used. If this option is disabled, Sparse does not + * preferentially search the diagonal. Because of this, Sparse + * has a wider variety of pivot candidates available, and so + * presumably fewer fill-ins will be created. However, the + * initial pivot selection process will take considerably longer. + * If working with node admittance matrices, or other matrices + * with a strong diagonal, it is probably best to use + * \a DIAGONAL_PIVOTING for two reasons. First, accuracy will be + * better because pivots will be chosen from the large diagonal + * elements, thus reducing the chance of growth. Second, a near + * optimal ordering will be chosen quickly. If the class of + * matrices you are working with does not have a strong diagonal, + * do not use \a DIAGONAL_PIVOTING, but consider using a larger + * threshold. When \a DIAGONAL_PIVOTING is turned off, the following + * options and constants are not used: \a MODIFIED_MARKOWITZ, + * \a MAX_MARKOWITZ_TIES, and \a TIES_MULTIPLIER. + */ +#define DIAGONAL_PIVOTING YES + +/*! + * This determines whether arrays start at an index of zero or one. + * This option is necessitated by the fact that standard C + * convention dictates that arrays begin with an index of zero but + * the standard mathematic convention states that arrays begin with + * an index of one. So if you prefer to start your arrays with + * zero, or your calling Sparse from FORTRAN, set ARRAY_OFFSET to + * NO or 0. Otherwise, set ARRAY_OFFSET to YES or 1. Note that if + * you use an offset of one, the arrays that you pass to Sparse + * must have an allocated length of one plus the size of the + * matrix. ARRAY_OFFSET must be either 0 or 1, no other offsets + * are valid. + */ +#define ARRAY_OFFSET YES + +/*! + * This specifies that the modified Markowitz method of pivot + * selection is to be used. The modified Markowitz method differs + * from standard Markowitz in two ways. First, under modified + * Markowitz, the search for a pivot can be terminated early if a + * adequate (in terms of sparsity) pivot candidate is found. + * Thus, when using modified Markowitz, the initial factorization + * can be faster, but at the expense of a suboptimal pivoting + * order that may slow subsequent factorizations. The second + * difference is in the way modified Markowitz breaks Markowitz + * ties. When two or more elements are pivot candidates and they + * all have the same Markowitz product, then the tie is broken by + * choosing the element that is best numerically. The numerically + * best element is the one with the largest ratio of its magnitude + * to the magnitude of the largest element in the same column, + * excluding itself. The modified Markowitz method results in + * marginally better accuracy. This option is most appropriate + * for use when working with very large matrices where the initial + * factor time represents an unacceptable burden. \a NO is recommended. + */ +#define MODIFIED_MARKOWITZ NO + +/*! + * This specifies that the spDeleteRowAndCol() routine + * should be compiled. Note that for this routine to be + * compiled, both \a DELETE and \a TRANSLATE should be set true. + */ +#define DELETE NO + +/*! + * This specifies that the spStripFills() routine should be compiled. + */ +#define STRIP NO + +/*! + * This specifies that the routine that preorders modified node + * admittance matrices should be compiled. This routine results + * in greater speed and accuracy if used with this type of + * matrix. + */ +#define MODIFIED_NODAL YES + +/*! + * This specifies that the routines that allow four related + * elements to be entered into the matrix at once should be + * compiled. These elements are usually related to an + * admittance. The routines affected by \a QUAD_ELEMENT are the + * spGetAdmittance(), spGetQuad() and spGetOnes() routines. + */ +#define QUAD_ELEMENT NO + +/*! + * This specifies that the routines that solve the matrix as if + * it was transposed should be compiled. These routines are + * useful when performing sensitivity analysis using the adjoint + * method. + */ +#define TRANSPOSE YES + +/*! + * This specifies that the routine that performs scaling on the + * matrix should be complied. Scaling is not strongly + * supported. The routine to scale the matrix is provided, but + * no routines are provided to scale and descale the RHS and + * Solution vectors. It is suggested that if scaling is desired, + * it only be preformed when the pivot order is being chosen [in + * spOrderAndFactor()]. This is the only time scaling has + * an effect. The scaling may then either be removed from the + * solution by the user or the scaled factors may simply be + * thrown away. \a NO is recommended. + */ +#define SCALING NO + +/*! + * This specifies that routines that are used to document the + * matrix, such as spPrint() and spFileMatrix(), should be + * compiled. + */ +#define DOCUMENTATION YES + +/*! + * This specifies that routines that are used to multily the + * matrix by a vector, such as spMultiply() and spMultTransposed(), should be + * compiled. + */ +#define MULTIPLICATION YES + +/*! + * This specifies that the routine spDeterminant() should be complied. + */ +#define DETERMINANT YES + +/*! + * This specifies that spLargestElement() and spRoundoff() should + * be compiled. These routines are used to check the stability (and + * hence the quality of the pivoting) of the factorization by + * computing a bound on the size of the element is the matrix + * \f$ E = A - LU \f$. If this bound is very high after applying + * spOrderAndFactor(), then the pivot threshold should be raised. + * If the bound increases greatly after using spFactor(), then the + * matrix should probably be reordered. Recomend \a NO. + */ +#define STABILITY NO + +/*! + * This specifies that spCondition() and spNorm(), the code that + * computes a good estimate of the condition number of the matrix, + * should be compiled. Recomend \a NO. + */ +#define CONDITION NO + +/*! + * This specifies that spPseudoCondition(), the code that computes + * a crude and easily fooled indicator of ill-conditioning in the + * matrix, should be compiled. Recomend \a NO. + */ +#define PSEUDOCONDITION NO + +/*! + * This specifies that the \a FORTRAN interface routines should be + * compiled. When interfacing to \a FORTRAN programs, the \a ARRAY_OFFSET + * options should be set to NO. + */ +#define FORTRAN NO + +/*! + * This specifies that additional error checking will be compiled. + * The type of error checked are those that are common when the + * matrix routines are first integrated into a user's program. Once + * the routines have been integrated in and are running smoothly, this + * option should be turned off. \a YES is recommended. + */ +#define DEBUG YES + +#endif /* spINSIDE_SPARSE */ + +/* + * The following options affect Sparse exports and so are exported as a + * side effect. For this reason they use the `sp' prefix. The boolean + * constants YES an NO are not defined in spMatrix.h to avoid conflicts + * with user code, so use 0 for NO and 1 for YES. + */ + +/*! + * This specifies that the routines will be complied to handle + * complex systems of equations. + */ +#define spCOMPLEX 1 + +/*! + * This specifies the format for complex vectors. If this is set + * false then a complex vector is made up of one double sized + * array of RealNumber's in which the real and imaginary numbers + * are placed alternately in the array. In other + * words, the first entry would be Complex[1].Real, then comes + * Complex[1].Imag, then Complex[2].Real, etc. If + * \a spSEPARATED_COMPLEX_VECTORS is set true, then each complex + * vector is represented by two arrays of \a spREALs, one with + * the real terms, the other with the imaginary. \a NO is recommended. + */ +#define spSEPARATED_COMPLEX_VECTORS 1 + +#ifdef spINSIDE_SPARSE + + + + + + + +/* + * MATRIX CONSTANTS + * + * These constants are used throughout the sparse matrix routines. They + * should be set to suit the type of matrix being solved. + */ + +/* Begin constants. */ + +/*! + * The relative threshold used if the user enters an invalid + * threshold. Also the threshold used by spFactor() when + * calling spOrderAndFactor(). The default threshold should + * not be less than or equal to zero nor larger than one. + * 0.001 is recommended. + */ +#define DEFAULT_THRESHOLD 1.0e-3 + +/*! + * This indicates whether spOrderAndFactor() should use diagonal + * pivoting as default. This issue only arises when + * spOrderAndFactor() is called from spFactor(). \a YES is recommended. + */ +#define DIAG_PIVOTING_AS_DEFAULT YES + +/*! + * This number multiplied by the size of the matrix equals the number + * of elements for which memory is initially allocated in spCreate(). + * 6 is recommended. + */ +#define SPACE_FOR_ELEMENTS 6 + +/*! + * This number multiplied by the size of the matrix equals the number + * of elements for which memory is initially allocated and specifically + * reserved for fill-ins in spCreate(). 4 is recommended. + */ +#define SPACE_FOR_FILL_INS 4 + +/*! + * The number of matrix elements requested from the malloc utility on + * each call to it. Setting this value greater than 1 reduces the + * amount of overhead spent in this system call. On a virtual memory + * machine, its good to allocate slightly less than a page worth of + * elements at a time (or some multiple thereof). + * 31 is recommended. + */ +#define ELEMENTS_PER_ALLOCATION 31 + +/*! + * The minimum allocated size of a matrix. Note that this does not + * limit the minimum size of a matrix. This just prevents having to + * resize a matrix many times if the matrix is expandable, large and + * allocated with an estimated size of zero. This number should not + * be less than one. + */ +#define MINIMUM_ALLOCATED_SIZE 6 + +/*! + * The amount the allocated size of the matrix is increased when it + * is expanded. + */ +#define EXPANSION_FACTOR 1.5 + +/*! + * Some terminology should be defined. The Markowitz row count is the number + * of non-zero elements in a row excluding the one being considered as pivot. + * There is one Markowitz row count for every row. The Markowitz column + * is defined similarly for columns. The Markowitz product for an element + * is the product of its row and column counts. It is a measure of how much + * work would be required on the next step of the factorization if that + * element were chosen to be pivot. A small Markowitz product is desirable. + * + * This number is used for two slightly different things, both of which + * relate to the search for the best pivot. First, it is the maximum + * number of elements that are Markowitz tied that will be sifted + * through when trying to find the one that is numerically the best. + * Second, it creates an upper bound on how large a Markowitz product + * can be before it eliminates the possibility of early termination + * of the pivot search. In other words, if the product of the smallest + * Markowitz product yet found and \a TIES_MULTIPLIER is greater than + * \a MAX_MARKOWITZ_TIES, then no early termination takes place. + * Set \a MAX_MARKOWITZ_TIES to some small value if no early termination of + * the pivot search is desired. An array of RealNumbers is allocated + * of size \a MAX_MARKOWITZ_TIES so it must be positive and shouldn't + * be too large. Active when MODIFIED_MARKOWITZ is 1 (YES). + * 100 is recommended. + * \see TIES_MULTIPLIER + */ +#define MAX_MARKOWITZ_TIES 100 + +/*! + * Specifies the number of Markowitz ties that are allowed to occur + * before the search for the pivot is terminated early. Set to some + * large value if no early termination of the pivot search is desired. + * This number is multiplied times the Markowitz product to determine + * how many ties are required for early termination. This means that + * more elements will be searched before early termination if a large + * number of fill-ins could be created by accepting what is currently + * considered the best choice for the pivot. Active when + * \a MODIFIED_MARKOWITZ is 1 (YES). Setting this number to zero + * effectively eliminates all pivoting, which should be avoided. + * This number must be positive. \a TIES_MULTIPLIER is also used when + * diagonal pivoting breaks down. 5 is recommended. + * \see MAX_MARKOWITZ_TIES + */ +#define TIES_MULTIPLIER 5 + +/*! + * Which partition mode is used by spPartition() as default. + * Possibilities include \a spDIRECT_PARTITION (each row used direct + * addressing, best for a few relatively dense matrices), + * \a spINDIRECT_PARTITION (each row used indirect addressing, best + * for a few very sparse matrices), and \a spAUTO_PARTITION (direct or + * indirect addressing is chosen on a row-by-row basis, carries a large + * overhead, but speeds up both dense and sparse matrices, best if there + * is a large number of matrices that can use the same ordering. + */ +#define DEFAULT_PARTITION spAUTO_PARTITION + +/*! + * The number of characters per page width. Set to 80 for terminal, + * 132 for line printer. Controls how many columns printed by + * spPrint() per page width. + */ +#define PRINTER_WIDTH 80 + + + + + + + + + + +#endif /* spINSIDE_SPARSE */ +/* + * PORTABILITY MACROS + */ + +#ifdef __STDC__ +# define spcCONCAT(prefix,suffix) prefix ## suffix +# define spcQUOTE(x) # x +# define spcFUNC_NEEDS_FILE(func,file) \ + func ## _requires_ ## file ## _to_be_included_ +#else +# define spcCONCAT(prefix,suffix) prefix/**/suffix +# define spcQUOTE(x) "x" +# define spcFUNC_NEEDS_FILE(func,file) \ + func/**/_requires_/**/file/**/_to_be_included_ +#endif + +#if defined(__cplusplus) || defined(c_plusplus) + /* + * Definitions for C++ + */ +# define spcEXTERN extern "C" +# define spcNO_ARGS +# define spcCONST const + typedef void *spGenericPtr; +#else +#ifdef __STDC__ + /* + * Definitions for ANSI C + */ +# define spcEXTERN extern +# define spcNO_ARGS void +# define spcCONST const + typedef void *spGenericPtr; +# else + /* + * Definitions for K&R C -- ignore function prototypes + */ +# define spcEXTERN extern +# define spcNO_ARGS +# define spcCONST + typedef char *spGenericPtr; +#endif +#endif + +#ifdef spINSIDE_SPARSE + + + + + + + +/* + * MACHINE CONSTANTS + * + * These numbers must be updated when the program is ported to a new machine. + */ + +/* Begin machine constants. */ +#include +#include + +/*! The resolution of spREAL. */ +#define MACHINE_RESOLUTION DBL_EPSILON + +/*! The largest possible value of spREAL. */ +#define LARGEST_REAL DBL_MAX + +/*! The smalles possible positive value of spREAL. */ +#define SMALLEST_REAL DBL_MIN + +/*! The largest possible value of shorts. */ +#define LARGEST_SHORT_INTEGER SHRT_MAX + +/*! The largest possible value of longs. */ +#define LARGEST_LONG_INTEGER LONG_MAX + + + + + + +/* ANNOTATION */ +/*! + * This macro changes the amount of annotation produced by the matrix + * routines. The annotation is used as a debugging aid. Change the number + * associated with \a ANNOTATE to change the amount of annotation produced by + * the program. Possible values include \a NONE, \a ON_STRANGE_BEHAVIOR, and + * \a FULL. \a NONE is recommended. + */ +#define ANNOTATE NONE + +/*! + * A possible value for \a ANNOTATE. Disables all annotation. + */ +#define NONE 0 + +/*! + * A possible value for \a ANNOTATE. Causes annotation to be produce + * upon unusual occurances only. + */ +#define ON_STRANGE_BEHAVIOR 1 + +/*! + * A possible value for \a ANNOTATE. Enables full annotation. + */ +#define FULL 2 + +#endif /* spINSIDE_SPARSE */ +#endif /* spCONFIG_DEFS */ diff --git a/src/maths/sparse/spdefs.h b/src/maths/sparse/spDefs.h similarity index 73% rename from src/maths/sparse/spdefs.h rename to src/maths/sparse/spDefs.h index 9ff853183..8bc762ad1 100644 --- a/src/maths/sparse/spdefs.h +++ b/src/maths/sparse/spDefs.h @@ -1,5 +1,3 @@ -#ifndef ngspice_SPDEFS_H -#define ngspice_SPDEFS_H /* * DATA STRUCTURE AND MACRO DEFINITIONS for Sparse. * @@ -15,30 +13,67 @@ /* * Revision and copyright information. * - * Copyright (c) 1985,86,87,88,89,90 - * by Kenneth S. Kundert and the University of California. + * Copyright (c) 1985-2003 by Kenneth S. Kundert * - * 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. + * $Date: 2003/06/29 04:19:52 $ + * $Revision: 1.2 $ */ /* - * IMPORTS + * If running lint, change some of the compiler options to get a more + * complete inspection. */ -#include +#ifdef lint +#undef REAL +#undef spCOMPLEX +#undef EXPANDABLE +#undef TRANSLATE +#undef INITIALIZE +#undef DELETE +#undef STRIP +#undef MODIFIED_NODAL +#undef QUAD_ELEMENT +#undef TRANSPOSE +#undef SCALING +#undef DOCUMENTATION +#undef MULTIPLICATION +#undef DETERMINANT +#undef CONDITION +#undef PSEUDOCONDITION +#undef FORTRAN +#undef DEBUG + +#define REAL YES +#define spCOMPLEX YES +#define EXPANDABLE YES +#define TRANSLATE YES +#define INITIALIZE YES +#define DELETE YES +#define STRIP YES +#define MODIFIED_NODAL YES +#define QUAD_ELEMENT YES +#define TRANSPOSE YES +#define SCALING YES +#define DOCUMENTATION YES +#define MULTIPLICATION YES +#define DETERMINANT YES +#define CONDITION YES +#define PSEUDOCONDITION YES +#define FORTRAN YES +#define DEBUG YES + +#define LINT YES +#else /* not lint */ +#define LINT NO +#endif /* not lint */ + + + -#undef ABORT -#undef FREE @@ -46,9 +81,10 @@ * MACRO DEFINITIONS * * Macros are distinguished by using solely capital letters in their - * identifiers. This contrasts with C defined identifiers which are - * strictly lower case, and program variable and procedure names - * which use both upper and lower case. */ + * identifiers. This contrasts with C defined identifiers which are strictly + * lower case, and program variable and procedure names which use both upper + * and lower case. + */ /* Begin macros. */ @@ -56,15 +92,32 @@ #define BOOLEAN int #define NO 0 #define YES 1 +#define NOT ! +#define AND && +#define OR || -#define SPARSE_ID 0x772773 /* Arbitrary (is Sparse on phone). */ -#define IS_SPARSE(matrix) ((matrix) != NULL && \ - (matrix)->ID == SPARSE_ID) -#define IS_VALID(matrix) ((matrix) != NULL && \ - (matrix)->ID == SPARSE_ID && \ - (matrix)->Error >= spOKAY && \ - (matrix)->Error < spFATAL) -#define IS_FACTORED(matrix) ((matrix)->Factored && !(matrix)->NeedsOrdering) +/* NULL pointer */ +#ifndef NULL +#define NULL 0 +#endif + +/* Define macros for validating matrix. */ +#define SPARSE_ID 0xDeadBeef /* Arbitrary. */ +#define IS_SPARSE(matrix) (((matrix) != NULL) AND \ + ((matrix)->ID == SPARSE_ID)) +#define NO_ERRORS(matrix) (((matrix)->Error >= spOKAY) AND \ + ((matrix)->Error < spFATAL)) +#define IS_FACTORED(matrix) ((matrix)->Factored AND \ + NOT (matrix)->NeedsOrdering) + +#define ASSERT_IS_SPARSE(matrix) vASSERT( IS_SPARSE(matrix), \ + spcMatrixIsNotValid ) +#define ASSERT_NO_ERRORS(matrix) vASSERT( NO_ERRORS(matrix), \ + spcErrorsMustBeCleared ) +#define ASSERT_IS_FACTORED(matrix) vASSERT( IS_FACTORED(matrix), \ + spcMatrixMustBeFactored ) +#define ASSERT_IS_NOT_FACTORED(matrix) vASSERT( NOT (matrix)->Factored, \ + spcMatrixMustNotBeFactored ) /* Macro commands */ /* Macro functions that return the maximum or minimum independent of type. */ @@ -78,36 +131,20 @@ #define SQR(a) ((a)*(a)) /* Macro procedure that swaps two entities. */ -#define SWAP(type, a, b) \ - do { \ - type SWAP_macro_local = a; \ - a = b; \ - b = SWAP_macro_local; \ - } while(0) +#define SWAP(type, a, b) {type swapx; swapx = a; a = b; b = swapx;} +/* + * COMPLEX OPERATION MACROS + */ +#ifndef ngspice_COMPLEX_H -/* Real and Complex numbers definition */ - -#define spREAL double - -/* Begin `realNumber'. */ -typedef spREAL RealNumber, *RealVector; - -/* Begin `ComplexNumber'. */ -typedef struct -{ RealNumber Real; - RealNumber Imag; -} ComplexNumber, *ComplexVector; - -/* Macro function that returns the approx absolute value of a complex - number. */ +/* Macro function that returns the approx absolute value of a complex number. */ +#if spCOMPLEX #define ELEMENT_MAG(ptr) (ABS((ptr)->Real) + ABS((ptr)->Imag)) - -#define CMPLX_ASSIGN_VALUE(cnum, vReal, vImag) \ -{ (cnum).Real = vReal; \ - (cnum).Imag = vImag; \ -} +#else +#define ELEMENT_MAG(ptr) ((ptr)->Real < 0.0 ? -(ptr)->Real : (ptr)->Real) +#endif /* Complex assignment statements. */ #define CMPLX_ASSIGN(to,from) \ @@ -126,21 +163,12 @@ typedef struct { (to).Real = -(from).Real; \ (to).Imag = (from).Imag; \ } - #define CMPLX_CONJ(a) (a).Imag = -(a).Imag - -#define CONJUGATE(a) (a).Imag = -(a).Imag - #define CMPLX_NEGATE(a) \ { (a).Real = -(a).Real; \ (a).Imag = -(a).Imag; \ } -#define CMPLX_NEGATE_SELF(cnum) \ -{ (cnum).Real = -(cnum).Real; \ - (cnum).Imag = -(cnum).Imag; \ -} - /* Macro that returns the approx magnitude (L-1 norm) of a complex number. */ #define CMPLX_1_NORM(a) (ABS((a).Real) + ABS((a).Imag)) @@ -148,7 +176,7 @@ typedef struct #define CMPLX_INF_NORM(a) (MAX (ABS((a).Real),ABS((a).Imag))) /* Macro function that returns the magnitude (L-2 norm) of a complex number. */ -#define CMPLX_2_NORM(a) (hypot((a).Real, (a).Imag)) +#define CMPLX_2_NORM(a) (sqrt((a).Real*(a).Real + (a).Imag*(a).Imag)) /* Macro function that performs complex addition. */ #define CMPLX_ADD(to,from_a,from_b) \ @@ -156,11 +184,6 @@ typedef struct (to).Imag = (from_a).Imag + (from_b).Imag; \ } -/* Macro function that performs addition of a complex and a scalar. */ -#define CMPLX_ADD_SELF_SCALAR(cnum, scalar) \ -{ (cnum).Real += scalar; \ -} - /* Macro function that performs complex subtraction. */ #define CMPLX_SUBT(to,from_a,from_b) \ { (to).Real = (from_a).Real - (from_b).Real; \ @@ -178,7 +201,7 @@ typedef struct { (to).Real -= (from).Real; \ (to).Imag -= (from).Imag; \ } - + /* Macro function that multiplies a complex number by a scalar. */ #define SCLR_MULT(to,sclr,cmplx) \ { (to).Real = (sclr) * (cmplx).Real; \ @@ -198,32 +221,13 @@ typedef struct (to).Imag = (from_a).Real * (from_b).Imag + \ (from_a).Imag * (from_b).Real; \ } - -/* Macro function that multiplies a complex number and a scalar. */ -#define CMPLX_MULT_SCALAR(to,from, scalar) \ -{ (to).Real = (from).Real * scalar; \ - (to).Imag = (from).Imag * scalar; \ -} - -/* Macro function that implements *= for a complex and a scalar number. */ - -#define CMPLX_MULT_SELF_SCALAR(cnum, scalar) \ -{ (cnum).Real *= scalar; \ - (cnum).Imag *= scalar; \ -} - -/* Macro function that multiply-assigns a complex number by a scalar. */ -#define SCLR_MULT_ASSIGN(to,sclr) \ -{ (to).Real *= (sclr); \ - (to).Imag *= (sclr); \ -} /* Macro function that implements to *= from for complex numbers. */ #define CMPLX_MULT_ASSIGN(to,from) \ -{ RealNumber to_Real_ = (to).Real; \ - (to).Real = to_Real_ * (from).Real - \ +{ RealNumber to_real_ = (to).Real; \ + (to).Real = to_real_ * (from).Real - \ (to).Imag * (from).Imag; \ - (to).Imag = to_Real_ * (from).Imag + \ + (to).Imag = to_real_ * (from).Imag + \ (to).Imag * (from).Real; \ } @@ -309,8 +313,8 @@ typedef struct /* Complex division: to = num / den */ #define CMPLX_DIV(to,num,den) \ { RealNumber r_, s_; \ - if (((den).Real >= (den).Imag && (den).Real > -(den).Imag) || \ - ((den).Real < (den).Imag && (den).Real <= -(den).Imag)) \ + if (((den).Real >= (den).Imag AND (den).Real > -(den).Imag) OR \ + ((den).Real < (den).Imag AND (den).Real <= -(den).Imag)) \ { r_ = (den).Imag / (den).Real; \ s_ = (den).Real + r_*(den).Imag; \ (to).Real = ((num).Real + r_*(num).Imag)/s_; \ @@ -327,8 +331,8 @@ typedef struct /* Complex division and assignment: num /= den */ #define CMPLX_DIV_ASSIGN(num,den) \ { RealNumber r_, s_, t_; \ - if (((den).Real >= (den).Imag && (den).Real > -(den).Imag) || \ - ((den).Real < (den).Imag && (den).Real <= -(den).Imag)) \ + if (((den).Real >= (den).Imag AND (den).Real > -(den).Imag) OR \ + ((den).Real < (den).Imag AND (den).Real <= -(den).Imag)) \ { r_ = (den).Imag / (den).Real; \ s_ = (den).Real + r_*(den).Imag; \ t_ = ((num).Real + r_*(num).Imag)/s_; \ @@ -347,8 +351,8 @@ typedef struct /* Complex reciprocation: to = 1.0 / den */ #define CMPLX_RECIPROCAL(to,den) \ { RealNumber r_; \ - if (((den).Real >= (den).Imag && (den).Real > -(den).Imag) || \ - ((den).Real < (den).Imag && (den).Real <= -(den).Imag)) \ + if (((den).Real >= (den).Imag AND (den).Real > -(den).Imag) OR \ + ((den).Real < (den).Imag AND (den).Real <= -(den).Imag)) \ { r_ = (den).Imag / (den).Real; \ (to).Imag = -r_*((to).Real = 1.0/((den).Real + r_*(den).Imag)); \ } \ @@ -360,40 +364,184 @@ typedef struct - - - -/* Allocation */ - -extern void * tmalloc(size_t); -extern void txfree(const void *); -extern void * trealloc(const void *, size_t); - -#define SP_MALLOC(type,number) (type *) tmalloc((size_t)(number) * sizeof(type)) -#define SP_REALLOC(ptr,type,number) \ - ptr = (type *) trealloc(ptr, (size_t)(number) * sizeof(type)) -#define SP_FREE(ptr) { if ((ptr) != NULL) txfree(ptr); (ptr) = NULL; } - - -#include "ngspice/config.h" - -/* A new calloc */ -#ifndef HAVE_LIBGC -#define SP_CALLOC(ptr,type,number) \ -{ ptr = (type *) calloc((size_t)(number), sizeof(type)); \ -} -#else /* HAVE_LIBCG */ -#define SP_CALLOC(ptr,type,number) \ -{ ptr = (type *) tmalloc((size_t)(number) * sizeof(type)); \ -} -#include -#define tmalloc(m) GC_malloc(m) -#define trealloc(m, n) GC_realloc((m), (n)) -#define tfree(m) -#define txfree(m) #endif -#include "ngspice/defines.h" + + +/* + * ASSERT and ABORT + * + * Macro used to assert that if the code is working correctly, then + * a condition must be true. If not, then execution is terminated + * and an error message is issued stating that there is an internal + * error and giving the file and line number. These assertions are + * not evaluated unless the DEBUG flag is true. + */ + +#if DEBUG +#define ASSERT(condition) \ +{ if (NOT(condition)) \ + { (void)fflush(stdout); \ + (void)fprintf(stderr, "sparse: internal error detected in file `%s' at line %d.\n assertion `%s' failed.\n",\ + __FILE__, __LINE__, spcQUOTE(condition) ); \ + (void)fflush(stderr); \ + abort(); \ + } \ +} +#else +#define ASSERT(condition) +#endif + +#if DEBUG +#define vASSERT(condition,message) \ +{ if (NOT(condition)) \ + vABORT(message); \ +} +#else +#define vASSERT(condition,message) +#endif + +#if DEBUG +#define vABORT(message) \ +{ (void)fflush(stdout); \ + (void)fprintf(stderr, "sparse: internal error detected in file `%s' at line %d.\n %s.\n", __FILE__, __LINE__, message );\ + (void)fflush(stderr); \ + abort(); \ +} + +#define ABORT() \ +{ (void)fflush(stdout); \ + (void)fprintf(stderr, "sparse: internal error detected in file `%s' at line %d.\n", __FILE__, __LINE__ ); \ + (void)fflush(stderr); \ + abort(); \ +} +#else +#define vABORT(message) abort() +#define ABORT() abort() +#endif + + + + + + +/* + * IMAGINARY VECTORS + * + * The imaginary vectors iRHS and iSolution are only needed when the + * options spCOMPLEX and spSEPARATED_COMPLEX_VECTORS are set. The following + * macro makes it easy to include or exclude these vectors as needed. + */ + +#if spCOMPLEX AND spSEPARATED_COMPLEX_VECTORS +#define IMAG_VECTORS , iRHS, iSolution +#define IMAG_RHS , iRHS +#define IMAG_RHS_DECL , RealVector iRHS +#define IMAG_VECT_DECL , RealVector iRHS, RealVector iSolution +#else +#define IMAG_VECTORS +#define IMAG_RHS +#define IMAG_RHS_DECL +#define IMAG_VECT_DECL +#endif + + + + + + +/* + * MEMORY ALLOCATION + */ +#include +spcEXTERN void *malloc(size_t size); +spcEXTERN void *calloc(size_t nmemb, size_t size); +spcEXTERN void *realloc(void *ptr, size_t size); +spcEXTERN void free(void *ptr); +spcEXTERN void abort(void); + +#define ALLOC(type,number) ((type *)malloc((unsigned)(sizeof(type)*(number)))) +#define REALLOC(ptr,type,number) \ + ptr = (type *)realloc((char *)ptr,(unsigned)(sizeof(type)*(number))) +#define FREE(ptr) { if ((ptr) != NULL) free((char *)(ptr)); (ptr) = NULL; } + + +/* Calloc that properly handles allocating a cleared vector. */ +#define CALLOC(ptr,type,number) \ +{ int i; ptr = ALLOC(type, number); \ + if (ptr != (type *)NULL) \ + for(i=(number)-1;i>=0; i--) ptr[i] = (type) 0; \ +} + + + + + + + +/* + * Utility Functions + */ +/* + * Compute the product of two intergers while avoiding overflow. + * Used when computing Markowitz products. + */ + +#define spcMarkoProd(product, op1, op2) \ + if (( (op1) > LARGEST_SHORT_INTEGER AND (op2) != 0) OR \ + ( (op2) > LARGEST_SHORT_INTEGER AND (op1) != 0)) \ + { double fProduct = (double)(op1) * (double)(op2); \ + if (fProduct >= LARGEST_LONG_INTEGER) \ + (product) = LARGEST_LONG_INTEGER; \ + else \ + (product) = (long)fProduct; \ + } \ + else (product) = (op1)*(op2); + + + + + + +/* + * REAL NUMBER + */ + +/* Begin `RealNumber'. */ + +typedef spREAL RealNumber, *RealVector; + + + + + + + + +/* + * COMPLEX NUMBER DATA STRUCTURE + * + * >>> Structure fields: + * Real (RealNumber) + * The real portion of the number. Real must be the first + * field in this structure. + * Imag (RealNumber) + * The imaginary portion of the number. This field must follow + * immediately after Real. + */ + +/* Begin `ComplexNumber'. */ + +typedef struct +{ RealNumber Real; + RealNumber Imag; +} ComplexNumber, *ComplexVector; + + + + + + /* @@ -427,7 +575,7 @@ extern void * trealloc(const void *, size_t); * NextInCol contains a pointer to the next element in the column below * this element. If this element is the last nonzero in the column then * NextInCol contains NULL. - * pInitInfo (void *) + * pInitInfo (spGenericPtr) * Pointer to user data used for initialization of the matrix element. * Initialized to NULL. * @@ -442,15 +590,16 @@ extern void * trealloc(const void *, size_t); /* Begin `MatrixElement'. */ struct MatrixElement -{ - RealNumber Real; +{ RealNumber Real; +#if spCOMPLEX RealNumber Imag; +#endif int Row; int Col; struct MatrixElement *NextInRow; struct MatrixElement *NextInCol; #if INITIALIZE - void *pInitInfo; + spGenericPtr pInitInfo; #endif }; @@ -482,8 +631,7 @@ typedef ElementPtr *ArrayOfElementPtrs; /* Begin `AllocationRecord'. */ struct AllocationRecord -{ - void *AllocatedPtr; +{ void *AllocatedPtr; struct AllocationRecord *NextRecord; }; @@ -518,21 +666,11 @@ typedef struct AllocationRecord *AllocationListPtr; /* Begin `FillinListNodeStruct'. */ struct FillinListNodeStruct -{ - ElementPtr pFillinList; +{ ElementPtr pFillinList; int NumberOfFillinsInList; struct FillinListNodeStruct *Next; }; -/* Similar to above, but keeps track of the original Elements */ -/* Begin `ElementListNodeStruct'. */ -struct ElementListNodeStruct -{ - ElementPtr pElementList; - int NumberOfElementsInList; - struct ElementListNodeStruct *Next; -}; - @@ -566,7 +704,7 @@ struct ElementListNodeStruct * grow to when EXPANDABLE is set true and AllocatedSize is the largest * the matrix can get without requiring that the matrix frame be * reallocated. - * Complex (int) + * Complex (BOOLEAN) * The flag which indicates whether the matrix is complex (true) or * real. * CurrentSize (int) @@ -575,18 +713,19 @@ struct ElementListNodeStruct * rows and columns that have elements in them. * Diag (ArrayOfElementPtrs) * Array of pointers that points to the diagonal elements. - * DoCmplxDirect (int *) + * DoCmplxDirect (BOOLEAN *) * Array of flags, one for each column in matrix. If a flag is true * then corresponding column in a complex matrix should be eliminated * in spFactor() using direct addressing (rather than indirect * addressing). - * DoRealDirect (int *) + * DoRealDirect (BOOLEAN *) * Array of flags, one for each column in matrix. If a flag is true * then corresponding column in a real matrix should be eliminated * in spFactor() using direct addressing (rather than indirect * addressing). * Elements (int) - * The total number of elements present in matrix. + * The number of original elements (total elements minus fill ins) + * present in matrix. * Error (int) * The error status of the sparse matrix package. * ExtSize (int) @@ -597,7 +736,7 @@ struct ElementListNodeStruct * ExtToIntRowMap (int []) * An array that is used to convert external row numbers to internal * external row numbers. Present only if TRANSLATE option is set true. - * Factored (int) + * Factored (BOOLEAN) * Indicates if matrix has been factored. This flag is set true in * spFactor() and spOrderAndFactor() and set false in spCreate() * and spClear(). @@ -618,8 +757,8 @@ struct ElementListNodeStruct * array used during forward and backward substitution. It is * commonly called y when the forward and backward substitution process is * denoted Ax = b => Ly = b and Ux = y. - * InternalVectorsAllocated (int) - * A flag that indicates whether the Markowitz vectors and the + * InternalVectorsAllocated (BOOLEAN) + * A flag that indicates whether theMmarkowitz vectors and the * Intermediate vector have been created. * These vectors are created in spcCreateInternalVectors(). * IntToExtColMap (int []) @@ -642,19 +781,16 @@ struct ElementListNodeStruct * The maximum number of off-diagonal element in the rows of L, the * lower triangular matrix. This quantity is used when computing an * estimate of the roundoff error in the matrix. - * NeedsOrdering (int) + * NeedsOrdering (BOOLEAN) * This is a flag that signifies that the matrix needs to be ordered * or reordered. NeedsOrdering is set true in spCreate() and * spGetElement() or spGetAdmittance() if new elements are added to the * matrix after it has been previously factored. It is set false in * spOrderAndFactor(). - * NumberOfInterchangesIsOdd (int) + * NumberOfInterchangesIsOdd (BOOLEAN) * Flag that indicates the sum of row and column interchange counts * is an odd number. Used when determining the sign of the determinant. - * Originals (int) - * The number of original elements (total elements minus fill ins) - * present in matrix. - * Partitioned (int) + * Partitioned (BOOLEAN) * This flag indicates that the columns of the matrix have been * partitioned into two groups. Those that will be addressed directly * and those that will be addressed indirectly in spFactor(). @@ -664,7 +800,7 @@ struct ElementListNodeStruct * Row pivot was chosen from. * PivotSelectionMethod (char) * Character that indicates which pivot search method was successful. - * PreviousMatrixWasComplex (int) + * PreviousMatrixWasComplex (BOOLEAN) * This flag in needed to determine how to clear the matrix. When * dealing with real matrices, it is important that the imaginary terms * in the matrix elements be zero. Thus, if the previous matrix was @@ -673,11 +809,11 @@ struct ElementListNodeStruct * RelThreshold (RealNumber) * The magnitude an element must have relative to others in its row * to be considered as a pivot candidate, except as a last resort. - * Reordered (int) + * Reordered (BOOLEAN) * This flag signifies that the matrix has been reordered. It * is cleared in spCreate(), set in spMNA_Preorder() and * spOrderAndFactor() and is used in spPrint(). - * RowsLinked (int) + * RowsLinked (BOOLEAN) * A flag that indicates whether the row pointers exist. The AddByIndex * routines do not generate the row pointers, which are needed by some * of the other routines, such as spOrderAndFactor() and spScale(). @@ -734,44 +870,42 @@ struct ElementListNodeStruct /* Begin `MatrixFrame'. */ struct MatrixFrame -{ - RealNumber AbsThreshold; +{ RealNumber AbsThreshold; int AllocatedSize; int AllocatedExtSize; - int Complex; + BOOLEAN Complex; int CurrentSize; ArrayOfElementPtrs Diag; - int *DoCmplxDirect; - int *DoRealDirect; + BOOLEAN *DoCmplxDirect; + BOOLEAN *DoRealDirect; int Elements; int Error; int ExtSize; int *ExtToIntColMap; int *ExtToIntRowMap; - int Factored; + BOOLEAN Factored; int Fillins; ArrayOfElementPtrs FirstInCol; ArrayOfElementPtrs FirstInRow; unsigned long ID; RealVector Intermediate; - int InternalVectorsAllocated; + BOOLEAN InternalVectorsAllocated; int *IntToExtColMap; int *IntToExtRowMap; int *MarkowitzRow; int *MarkowitzCol; long *MarkowitzProd; int MaxRowCountInLowerTri; - int NeedsOrdering; - int NumberOfInterchangesIsOdd; - int Originals; - int Partitioned; + BOOLEAN NeedsOrdering; + BOOLEAN NumberOfInterchangesIsOdd; + BOOLEAN Partitioned; int PivotsOriginalCol; int PivotsOriginalRow; char PivotSelectionMethod; - int PreviousMatrixWasComplex; + BOOLEAN PreviousMatrixWasComplex; RealNumber RelThreshold; - int Reordered; - int RowsLinked; + BOOLEAN Reordered; + BOOLEAN RowsLinked; int SingularCol; int SingularRow; int Singletons; @@ -782,29 +916,32 @@ struct MatrixFrame int RecordsRemaining; ElementPtr NextAvailElement; int ElementsRemaining; - struct ElementListNodeStruct *FirstElementListNode; - struct ElementListNodeStruct *LastElementListNode; ElementPtr NextAvailFillin; int FillinsRemaining; struct FillinListNodeStruct *FirstFillinListNode; struct FillinListNodeStruct *LastFillinListNode; }; +typedef struct MatrixFrame *MatrixPtr; + + /* - * Function declarations + * Declarations */ -extern ElementPtr spcGetElement( MatrixPtr ); -extern ElementPtr spcGetFillin( MatrixPtr ); -extern ElementPtr spcFindElementInCol( MatrixPtr, ElementPtr*, int, int, int ); -extern ElementPtr spcCreateElement( MatrixPtr, int, int, ElementPtr*, int ); -extern void spcCreateInternalVectors( MatrixPtr ); -extern void spcLinkRows( MatrixPtr ); -extern void spcColExchange( MatrixPtr, int, int ); -extern void spcRowExchange( MatrixPtr, int, int ); - -void spErrorMessage(MatrixPtr, FILE *, char *); - -#endif +spcEXTERN ElementPtr spcGetElement( MatrixPtr ); +spcEXTERN ElementPtr spcGetFillin( MatrixPtr ); +spcEXTERN ElementPtr spcFindElementInCol( MatrixPtr, ElementPtr*, int, int, int ); +spcEXTERN ElementPtr spcFindDiag( MatrixPtr, int ); +spcEXTERN ElementPtr spcCreateElement( MatrixPtr, int, int, + ElementPtr*, ElementPtr*, int ); +spcEXTERN void spcCreateInternalVectors( MatrixPtr ); +spcEXTERN void spcLinkRows( MatrixPtr ); +spcEXTERN void spcColExchange( MatrixPtr, int, int ); +spcEXTERN void spcRowExchange( MatrixPtr, int, int ); +spcEXTERN char spcMatrixIsNotValid[]; +spcEXTERN char spcErrorsMustBeCleared[]; +spcEXTERN char spcMatrixMustBeFactored[]; +spcEXTERN char spcMatrixMustNotBeFactored[]; diff --git a/src/maths/sparse/spfactor.c b/src/maths/sparse/spFactor.c similarity index 57% rename from src/maths/sparse/spfactor.c rename to src/maths/sparse/spFactor.c index de5de6177..a1f67553e 100644 --- a/src/maths/sparse/spfactor.c +++ b/src/maths/sparse/spFactor.c @@ -4,10 +4,17 @@ * Author: Advising Professor: * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli * UC Berkeley - * + */ +/*! \file * This file contains the routines to factor the matrix into LU form. * - * >>> User accessible functions contained in this file: + * Objects that begin with the \a spc prefix are considered private + * and should not be used. + * + * \author + * Kenneth S. Kundert + */ +/* >>> User accessible functions contained in this file: * spOrderAndFactor * spFactor * spPartition @@ -22,28 +29,20 @@ * spcRowExchange spcColExchange * ExchangeColElements ExchangeRowElements * RealRowColElimination ComplexRowColElimination - * UpdateMarkowitzNumbers CreateFillin - * MatrixIsSingular ZeroPivot - * WriteStatus + * UpdateMarkowitzNumbers 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. + * Copyright (c) 1985-2004 + * by Kenneth S. Kundert */ + + /* * IMPORTS * @@ -55,31 +54,23 @@ * spDefs.h * Matrix type and macro definitions for the sparse matrix routines. */ -#include -#define spINSIDE_SPARSE -#include "spconfig.h" -#include "ngspice/spmatrix.h" -#include "spdefs.h" -#ifdef HAS_WINGUI -extern void SetAnalyse(char *Analyse, int Percent); -/* to increase responsiveness of Windows GUI */ -#define INCRESP \ -do { \ - static int ii = 100; \ - ii--;\ - if (ii == 0) { \ - SetAnalyse("or", 0); \ - ii = 100; \ - } \ -} while(0) -#endif +#define spINSIDE_SPARSE +#include +#include "spConfig.h" +#include "ngspice/spmatrix.h" +#include "spDefs.h" + + + + /* * Function declarations */ static int FactorComplexMatrix( MatrixPtr ); +//static void CreateInternalVectors( MatrixPtr ); static void CountMarkowitz( MatrixPtr, RealVector, int ); static void MarkowitzProducts( MatrixPtr, int ); static ElementPtr SearchForPivot( MatrixPtr, int, int ); @@ -91,41 +82,43 @@ 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 ); + ElementPtr, int ); static void ExchangeRowElements( MatrixPtr, int, ElementPtr, 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 ); +#if (ANNOTATE == FULL) +static void WriteStatus( MatrixPtr, int ); +#endif + -/* - * 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 + * into \a 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. + * Gauss's method where the pivots are associated with \a L and the + * diagonal terms of \a U are one. * - * >>> Returned: - * The error code is returned. Possible errors are listed below. + * \return + * The error code is returned. Possible errors are \a spNO_MEMORY, + * \a spSINGULAR and \a spSMALL_PIVOT. + * Error is cleared upon entering this function. * - * >>> Arguments: - * Matrix (char *) - * Pointer to matrix. - * RHS (RealVector) + * \param eMatrix + * Pointer to the matrix. + * \param RHS * 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 (RealNumber) + * \param RelThreshold * 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 @@ -135,7 +128,7 @@ static int ZeroPivot( MatrixPtr, int ); * 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 + * Setting the \a 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 @@ -148,27 +141,27 @@ static int ZeroPivot( MatrixPtr, int ); * 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 + * \a 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 (RealNumber) + * \param AbsThreshold * 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 + * elements, then \a AbsThreshold should be set to zero. + * \a 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 (int) + * \param DiagPivoting * 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 + * diagonal if possible. If \a DiagPivoting is nonzero and if + * \a 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 @@ -184,103 +177,98 @@ static int ZeroPivot( MatrixPtr, int ); * However, the initial pivot selection process takes considerably * longer for off-diagonal pivoting. * - * >>> Local variables: + * \see spFactor() + */ +/* >>> 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. */ -int -spOrderAndFactor(MatrixPtr Matrix, RealNumber RHS[], RealNumber RelThreshold, - RealNumber AbsThreshold, int DiagPivoting) +spError +spOrderAndFactor( + spMatrix eMatrix, + spREAL RHS[], + spREAL RelThreshold, + spREAL AbsThreshold, + int DiagPivoting +) { - ElementPtr pPivot; - int Step, Size, ReorderingRequired; - RealNumber LargestInCol; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +ElementPtr pPivot; +int Step, Size; +ElementPtr SearchForPivot(); +RealNumber LargestInCol, FindLargestInCol(); - /* Begin `spOrderAndFactor'. */ - assert( IS_VALID(Matrix) && !Matrix->Factored); +/* Begin `spOrderAndFactor'. */ + ASSERT_IS_SPARSE( Matrix ); + ASSERT_NO_ERRORS( Matrix ); + ASSERT_IS_NOT_FACTORED( Matrix ); Matrix->Error = spOKAY; Size = Matrix->Size; - if (RelThreshold <= 0.0) - RelThreshold = Matrix->RelThreshold; - if (RelThreshold > 1.0) - RelThreshold = Matrix->RelThreshold; + if (RelThreshold <= 0.0) RelThreshold = Matrix->RelThreshold; + if (RelThreshold > 1.0) RelThreshold = Matrix->RelThreshold; Matrix->RelThreshold = RelThreshold; - if (AbsThreshold < 0.0) - AbsThreshold = Matrix->AbsThreshold; + 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++) { -#ifdef HAS_WINGUI - /* macro to improve responsiveness of Windows GUI */ - INCRESP; -#endif - pPivot = Matrix->Diag[Step]; - if (!pPivot) { - fprintf(stderr, "Warning: spfactor.c, 230, Pivot for step = %d not found\n", Step); - ReorderingRequired = YES; - break; /* for loop */ - } + 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) + if ((LargestInCol * RelThreshold < ELEMENT_MAG(pPivot))) + { if (Matrix->Complex) ComplexRowColElimination( Matrix, pPivot ); else RealRowColElimination( Matrix, pPivot ); - } else { - ReorderingRequired = YES; + } + else + { Matrix->NeedsOrdering = YES; break; /* for loop */ } } - if (!ReorderingRequired) + if (NOT Matrix->NeedsOrdering) goto Done; - else { - /* A pivot was not large enough to maintain accuracy, so a - * partial reordering is required. */ + 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. */ + } /* 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 (!Matrix->RowsLinked) + if (NOT Matrix->RowsLinked) spcLinkRows( Matrix ); - if (!Matrix->InternalVectorsAllocated) + if (NOT Matrix->InternalVectorsAllocated) spcCreateInternalVectors( Matrix ); if (Matrix->Error >= spFATAL) return Matrix->Error; } - /* Form initial Markowitz products. */ +/* Form initial Markowitz products. */ CountMarkowitz( Matrix, RHS, Step ); MarkowitzProducts( Matrix, Step ); Matrix->MaxRowCountInLowerTri = -1; - /* Perform reordering and factorization. */ - for (; Step <= Size; Step++) { -#ifdef HAS_WINGUI - /* macro to improve responsiveness of Windows GUI */ - INCRESP; -#endif - pPivot = SearchForPivot( Matrix, Step, DiagPivoting ); +/* Perform reordering and factorization. */ + for (; Step <= Size; Step++) + { pPivot = SearchForPivot( Matrix, Step, DiagPivoting ); if (pPivot == NULL) return MatrixIsSingular( Matrix, Step ); ExchangeRowsAndCols( Matrix, pPivot, Step ); @@ -311,120 +299,115 @@ Done: -/* - * 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. + * 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" \a 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. + * \return + * The error code is returned. Possible errors are + * \a spNO_MEMORY, \a spSINGULAR, \a spZERO_DIAG and \a spSMALL_PIVOT. + * Error is cleared upon entering this function. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to matrix. - * - * >>> Possible errors: - * spNO_MEMORY - * spSINGULAR - * spZERO_DIAG - * spSMALL_PIVOT - * Error is cleared in this function. */ + * \see spOrderAndFactor() + */ -int -spFactor(MatrixPtr Matrix) +spError +spFactor( spMatrix eMatrix ) { - ElementPtr pElement; - ElementPtr pColumn; - int Step, Size; - RealNumber Mult; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register ElementPtr pColumn; +register int Step, Size; +RealNumber Mult; - /* Begin `spFactor'. */ - assert( IS_VALID(Matrix) && !Matrix->Factored); +/* Begin `spFactor'. */ + ASSERT_IS_SPARSE( Matrix ); + ASSERT_NO_ERRORS( Matrix ); + ASSERT_IS_NOT_FACTORED( Matrix ); - if (Matrix->NeedsOrdering) { - return spOrderAndFactor( Matrix, NULL, + if (Matrix->NeedsOrdering) + { return spOrderAndFactor( eMatrix, (RealVector)NULL, 0.0, 0.0, DIAG_PIVOTING_AS_DEFAULT ); } - if (!Matrix->Partitioned) spPartition( Matrix, spDEFAULT_PARTITION ); - if (Matrix->Complex) - return FactorComplexMatrix( Matrix ); + if (NOT Matrix->Partitioned) spPartition( eMatrix, spDEFAULT_PARTITION ); +#if spCOMPLEX + if (Matrix->Complex) return FactorComplexMatrix( Matrix ); +#endif +#if REAL Size = Matrix->Size; - if (Size == 0) { - Matrix->Factored = YES; - return (Matrix->Error = spOKAY); - } - 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; +/* Start factorization. */ + for (Step = 2; Step <= Size; Step++) + { if (Matrix->DoRealDirect[Step]) + { /* Update column using direct addressing scatter-gather. */ + register RealNumber *Dest = (RealNumber *)Matrix->Intermediate; - /* Scatter. */ +/* Scatter. */ pElement = Matrix->FirstInCol[Step]; - while (pElement != NULL) { - Dest[pElement->Row] = pElement->Real; + while (pElement != NULL) + { Dest[pElement->Row] = pElement->Real; pElement = pElement->NextInCol; } - /* Update column. */ +/* Update column. */ pColumn = Matrix->FirstInCol[Step]; - while (pColumn->Row < Step) { - pElement = Matrix->Diag[pColumn->Row]; + 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. */ +/* Gather. */ pElement = Matrix->Diag[Step]->NextInCol; - while (pElement != NULL) { - pElement->Real = Dest[pElement->Row]; + while (pElement != NULL) + { pElement->Real = Dest[pElement->Row]; pElement = pElement->NextInCol; } - /* Check for singular matrix. */ +/* Check for singular matrix. */ if (Dest[Step] == 0.0) return ZeroPivot( Matrix, Step ); Matrix->Diag[Step]->Real = 1.0 / Dest[Step]; - } else { - /* Update column using indirect addressing scatter-gather. */ - RealNumber **pDest = (RealNumber **)Matrix->Intermediate; + } + else + { /* Update column using indirect addressing scatter-gather. */ + register RealNumber **pDest = (RealNumber **)Matrix->Intermediate; - /* Scatter. */ +/* Scatter. */ pElement = Matrix->FirstInCol[Step]; - while (pElement != NULL) { - pDest[pElement->Row] = &pElement->Real; + while (pElement != NULL) + { pDest[pElement->Row] = &pElement->Real; pElement = pElement->NextInCol; } - /* Update column. */ +/* Update column. */ pColumn = Matrix->FirstInCol[Step]; - while (pColumn->Row < Step) { - pElement = Matrix->Diag[pColumn->Row]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; Mult = (*pDest[pColumn->Row] *= pElement->Real); while ((pElement = pElement->NextInCol) != NULL) *pDest[pElement->Row] -= Mult * pElement->Real; pColumn = pColumn->NextInCol; } - /* Check for singular matrix. */ +/* Check for singular matrix. */ if (Matrix->Diag[Step]->Real == 0.0) return ZeroPivot( Matrix, Step ); Matrix->Diag[Step]->Real = 1.0 / Matrix->Diag[Step]->Real; @@ -433,6 +416,7 @@ spFactor(MatrixPtr Matrix) Matrix->Factored = YES; return (Matrix->Error = spOKAY); +#endif /* REAL */ } @@ -440,6 +424,7 @@ spFactor(MatrixPtr Matrix) +#if spCOMPLEX /* * FACTOR COMPLEX MATRIX * @@ -459,197 +444,203 @@ spFactor(MatrixPtr Matrix) */ static int -FactorComplexMatrix( MatrixPtr Matrix ) +FactorComplexMatrix( MatrixPtr Matrix ) { - ElementPtr pElement; - ElementPtr pColumn; - int Step, Size; - ComplexNumber Mult, Pivot; +register ElementPtr pElement; +register ElementPtr pColumn; +register int Step, Size; +ComplexNumber Mult, Pivot; - /* Begin `FactorComplexMatrix'. */ - assert(Matrix->Complex); +/* Begin `FactorComplexMatrix'. */ + ASSERT(Matrix->Complex); Size = Matrix->Size; - - if (Size == 0) { - Matrix->Factored = YES; - return (Matrix->Error = spOKAY); - } - pElement = Matrix->Diag[1]; if (ELEMENT_MAG(pElement) == 0.0) return ZeroPivot( Matrix, 1 ); - /* Cmplx expr: *pPivot = 1.0 / *pPivot. */ +/* Cmplx expr: *pPivot = 1.0 / *pPivot. */ CMPLX_RECIPROCAL( *pElement, *pElement ); - /* Start factorization. */ - for (Step = 2; Step <= Size; Step++) { - if (Matrix->DoCmplxDirect[Step]) { - /* Update column using direct addressing scatter-gather. */ - ComplexNumber *Dest; +/* Start factorization. */ + for (Step = 2; Step <= Size; Step++) + { if (Matrix->DoCmplxDirect[Step]) + { /* Update column using direct addressing scatter-gather. */ + register ComplexNumber *Dest; Dest = (ComplexNumber *)Matrix->Intermediate; - /* Scatter. */ +/* Scatter. */ pElement = Matrix->FirstInCol[Step]; - while (pElement != NULL) { - Dest[pElement->Row] = *(ComplexNumber *)pElement; + while (pElement != NULL) + { Dest[pElement->Row] = *(ComplexNumber *)pElement; pElement = pElement->NextInCol; } - /* Update column. */ +/* Update column. */ pColumn = Matrix->FirstInCol[Step]; - while (pColumn->Row < Step) { - pElement = Matrix->Diag[pColumn->Row]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; /* Cmplx expr: Mult = Dest[pColumn->Row] * (1.0 / *pPivot). */ CMPLX_MULT(Mult, Dest[pColumn->Row], *pElement); CMPLX_ASSIGN(*pColumn, Mult); - while ((pElement = pElement->NextInCol) != NULL) { - /* Cmplx expr: Dest[pElement->Row] -= Mult * pElement */ + while ((pElement = pElement->NextInCol) != NULL) + { /* Cmplx expr: Dest[pElement->Row] -= Mult * pElement */ CMPLX_MULT_SUBT_ASSIGN(Dest[pElement->Row],Mult,*pElement); } pColumn = pColumn->NextInCol; } - /* Gather. */ +/* Gather. */ pElement = Matrix->Diag[Step]->NextInCol; - while (pElement != NULL) { - *(ComplexNumber *)pElement = Dest[pElement->Row]; + while (pElement != NULL) + { *(ComplexNumber *)pElement = Dest[pElement->Row]; pElement = pElement->NextInCol; } - /* Check for singular matrix. */ +/* Check for singular matrix. */ Pivot = Dest[Step]; if (CMPLX_1_NORM(Pivot) == 0.0) return ZeroPivot( Matrix, Step ); - CMPLX_RECIPROCAL( *Matrix->Diag[Step], Pivot ); - } else { - /* Update column using direct addressing scatter-gather. */ - ComplexNumber **pDest; + CMPLX_RECIPROCAL( *Matrix->Diag[Step], Pivot ); + } + else + { /* Update column using direct addressing scatter-gather. */ + register ComplexNumber **pDest; pDest = (ComplexNumber **)Matrix->Intermediate; - /* Scatter. */ +/* Scatter. */ pElement = Matrix->FirstInCol[Step]; - while (pElement != NULL) { - pDest[pElement->Row] = (ComplexNumber *)pElement; + while (pElement != NULL) + { pDest[pElement->Row] = (ComplexNumber *)pElement; pElement = pElement->NextInCol; } - /* Update column. */ +/* Update column. */ pColumn = Matrix->FirstInCol[Step]; - while (pColumn->Row < Step) { - pElement = Matrix->Diag[pColumn->Row]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; /* Cmplx expr: Mult = *pDest[pColumn->Row] * (1.0 / *pPivot). */ CMPLX_MULT(Mult, *pDest[pColumn->Row], *pElement); CMPLX_ASSIGN(*pDest[pColumn->Row], Mult); - while ((pElement = pElement->NextInCol) != NULL) { - /* Cmplx expr: *pDest[pElement->Row] -= Mult * pElement */ - CMPLX_MULT_SUBT_ASSIGN(*pDest[pElement->Row],Mult,*pElement); + while ((pElement = pElement->NextInCol) != NULL) + { /* Cmplx expr: *pDest[pElement->Row] -= Mult * pElement */ + CMPLX_MULT_SUBT_ASSIGN(*pDest[pElement->Row],Mult,*pElement); } pColumn = pColumn->NextInCol; } - /* Check for singular matrix. */ +/* Check for singular matrix. */ pElement = Matrix->Diag[Step]; if (ELEMENT_MAG(pElement) == 0.0) return ZeroPivot( Matrix, Step ); - CMPLX_RECIPROCAL( *pElement, *pElement ); + CMPLX_RECIPROCAL( *pElement, *pElement ); } } Matrix->Factored = YES; return (Matrix->Error = spOKAY); } +#endif /* spCOMPLEX */ -/* - * PARTITION MATRIX - * +/*! * This routine determines the cost to factor each row using both * direct and indirect addressing and decides, on a row-by-row basis, * which addressing mode is fastest. This information is used in * spFactor() to speed the factorization. * - * When factoring a previously ordered matrix using spFactor(), - * Sparse operates on a row-at-a-time basis. For speed, on each - * step, the row being updated is copied into a full vector and the - * operations are performed on that vector. This can be done one of - * two ways, either using direct addressing or indirect addressing. - * Direct addressing is fastest when the matrix is relatively dense - * and indirect addressing is best when the matrix is quite sparse. - * The user selects the type of partition used with Mode. If Mode is - * set to spDIRECT_PARTITION, then the all rows are placed in the - * direct addressing partition. Similarly, if Mode is set to - * spINDIRECT_PARTITION, then the all rows are placed in the indirect - * addressing partition. By setting Mode to spAUTO_PARTITION, the + * When factoring a previously ordered matrix using spFactor(), Sparse + * operates on a row-at-a-time basis. For speed, on each step, the + * row being updated is copied into a full vector and the operations + * are performed on that vector. This can be done one of two ways, + * either using direct addressing or indirect addressing. Direct + * addressing is fastest when the matrix is relatively dense and + * indirect addressing is best when the matrix is quite sparse. The + * user selects the type of partition used with \a Mode. If \a Mode is set + * to \a spDIRECT_PARTITION, then the all rows are placed in the direct + * addressing partition. Similarly, if \a Mode is set to + * \a spINDIRECT_PARTITION, then the all rows are placed in the indirect + * addressing partition. By setting \a Mode to \a spAUTO_PARTITION, the * user allows Sparse to select the partition for each row * individually. spFactor() generally runs faster if Sparse is * allowed to choose its own partitioning, however choosing a - * partition is expensive. The time required to choose a partition - * is of the same order of the cost to factor the matrix. If you - * plan to factor a large number of matrices with the same structure, - * it is best to let Sparse choose the partition. Otherwise, you - * should choose the partition based on the predicted density of the - * matrix. + * partition is expensive. The time required to choose a partition is + * of the same order of the cost to factor the matrix. If you plan to + * factor a large number of matrices with the same structure, it is + * best to let Sparse choose the partition. Otherwise, you should + * choose the partition based on the predicted density of the matrix. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to matrix. - * Mode (int) - * Mode must be one of three special codes: spDIRECT_PARTITION, - * spINDIRECT_PARTITION, or spAUTO_PARTITION. */ + * \param Mode + * Mode must be one of three special codes: \a spDIRECT_PARTITION, + * \a spINDIRECT_PARTITION, or \a spAUTO_PARTITION. + */ void -spPartition(MatrixPtr Matrix, int Mode) +spPartition( + spMatrix eMatrix, + int Mode +) { - ElementPtr pElement, pColumn; - int Step, Size; - int *Nc, *No, *Nm; - int *DoRealDirect, *DoCmplxDirect; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement, pColumn; +register int Step, Size; +register int *Nc, *No; +register long *Nm; +BOOLEAN *DoRealDirect, *DoCmplxDirect; + +/* Begin `spPartition'. */ + ASSERT_IS_SPARSE( Matrix ); - /* Begin `spPartition'. */ - assert( IS_SPARSE( Matrix ) ); if (Matrix->Partitioned) return; Size = Matrix->Size; DoRealDirect = Matrix->DoRealDirect; DoCmplxDirect = Matrix->DoCmplxDirect; Matrix->Partitioned = YES; - /* If partition is specified by the user, this is easy. */ +/* If partition is specified by the user, this is easy. */ if (Mode == spDEFAULT_PARTITION) Mode = DEFAULT_PARTITION; - if (Mode == spDIRECT_PARTITION) { - for (Step = 1; Step <= Size; Step++) { + if (Mode == spDIRECT_PARTITION) + { for (Step = 1; Step <= Size; Step++) +#if REAL DoRealDirect[Step] = YES; +#endif +#if spCOMPLEX DoCmplxDirect[Step] = YES; - } +#endif return; - } else if (Mode == spINDIRECT_PARTITION) { - for (Step = 1; Step <= Size; Step++) { + } + else if (Mode == spINDIRECT_PARTITION) + { for (Step = 1; Step <= Size; Step++) +#if REAL DoRealDirect[Step] = NO; +#endif +#if spCOMPLEX DoCmplxDirect[Step] = NO; - } +#endif return; - } else - assert( Mode == spAUTO_PARTITION ); + } + else vASSERT( Mode == spAUTO_PARTITION, "Invalid partition code" );; - /* Otherwise, count all operations needed in when factoring matrix. */ - Nc = Matrix->MarkowitzRow; - No = Matrix->MarkowitzCol; - Nm = (int *)Matrix->MarkowitzProd; +/* Otherwise, count all operations needed in when factoring matrix. */ + Nc = (int *)Matrix->MarkowitzRow; + No = (int *)Matrix->MarkowitzCol; + Nm = (long *)Matrix->MarkowitzProd; - /* Start mock-factorization. */ - for (Step = 1; Step <= Size; Step++) { - Nc[Step] = No[Step] = Nm[Step] = 0; +/* Start mock-factorization. */ + for (Step = 1; Step <= Size; Step++) + { Nc[Step] = No[Step] = Nm[Step] = 0; pElement = Matrix->FirstInCol[Step]; - while (pElement != NULL) { - Nc[Step]++; + while (pElement != NULL) + { Nc[Step]++; pElement = pElement->NextInCol; } pColumn = Matrix->FirstInCol[Step]; - while (pColumn->Row < Step) { - pElement = Matrix->Diag[pColumn->Row]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; Nm[Step]++; while ((pElement = pElement->NextInCol) != NULL) No[Step]++; @@ -657,43 +648,55 @@ spPartition(MatrixPtr Matrix, int Mode) } } - for (Step = 1; Step <= Size; Step++) { - /* The following are just estimates based on a count on the - * number of machine instructions used on each machine to - * perform the various tasks. It was assumed that each - * machine instruction required the same amount of time (I - * don't believe this is TRUE for the VAX, and have no idea if - * this is TRUE for the 68000 family). For optimum - * performance, these numbers should be tuned to the machine. - * - * Nc is the number of nonzero elements in the column. - * Nm is the number of multipliers in the column. - * No is the number of operations in the inner loop. */ + for (Step = 1; Step <= Size; Step++) + { +/* + * The following are just estimates based on a count on the number of + * machine instructions used on each machine to perform the various + * tasks. It was assumed that each machine instruction required the + * same amount of time (I don't believe this is true for the VAX, and + * have no idea if this is true for the 68000 family). For optimum + * performance, these numbers should be tuned to the machine. + * Nc is the number of nonzero elements in the column. + * Nm is the number of multipliers in the column. + * No is the number of operations in the inner loop. + */ #define generic #ifdef hp9000s300 +#if REAL DoRealDirect[Step] = (Nm[Step] + No[Step] > 3*Nc[Step] - 2*Nm[Step]); +#endif +#if spCOMPLEX /* On the hp350, it is never profitable to use direct for complex. */ DoCmplxDirect[Step] = NO; +#endif #undef generic #endif #ifdef vax +#if REAL DoRealDirect[Step] = (Nm[Step] + No[Step] > 3*Nc[Step] - 2*Nm[Step]); +#endif +#if spCOMPLEX DoCmplxDirect[Step] = (Nm[Step] + No[Step] > 7*Nc[Step] - 4*Nm[Step]); +#endif #undef generic #endif #ifdef generic +#if REAL DoRealDirect[Step] = (Nm[Step] + No[Step] > 3*Nc[Step] - 2*Nm[Step]); +#endif +#if spCOMPLEX DoCmplxDirect[Step] = (Nm[Step] + No[Step] > 7*Nc[Step] - 4*Nm[Step]); +#endif #undef generic #endif } #if (ANNOTATE == FULL) - { - int Ops = 0; + { int Ops = 0; for (Step = 1; Step <= Size; Step++) Ops += No[Step]; printf("Operation count for inner loop of factorization = %d.\n", Ops); @@ -717,10 +720,6 @@ spPartition(MatrixPtr Matrix, int Mode) * Matrix (MatrixPtr) * Pointer to matrix. * - * >>> Local variables: - * SizePlusOne (unsigned) - * Size of the arrays to be allocated. - * * >>> Possible errors: * spNO_MEMORY */ @@ -728,40 +727,51 @@ spPartition(MatrixPtr Matrix, int Mode) void spcCreateInternalVectors( MatrixPtr Matrix ) { - int Size; +int Size; - /* Begin `spcCreateInternalVectors'. */ - /* Create Markowitz arrays. */ +/* Begin `spcCreateInternalVectors'. */ +/* Create Markowitz arrays. */ Size= Matrix->Size; - if (Matrix->MarkowitzRow == NULL) { - if (( Matrix->MarkowitzRow = SP_MALLOC(int, Size+1)) == NULL) + if (Matrix->MarkowitzRow == NULL) + { if (( Matrix->MarkowitzRow = ALLOC(int, Size+1)) == NULL) Matrix->Error = spNO_MEMORY; } - if (Matrix->MarkowitzCol == NULL) { - if (( Matrix->MarkowitzCol = SP_MALLOC(int, Size+1)) == NULL) + if (Matrix->MarkowitzCol == NULL) + { if (( Matrix->MarkowitzCol = ALLOC(int, Size+1)) == NULL) Matrix->Error = spNO_MEMORY; } - if (Matrix->MarkowitzProd == NULL) { - if (( Matrix->MarkowitzProd = SP_MALLOC(long, Size+2)) == NULL) + if (Matrix->MarkowitzProd == NULL) + { if (( Matrix->MarkowitzProd = ALLOC(long, Size+2)) == NULL) Matrix->Error = spNO_MEMORY; } - /* Create DoDirect vectors for use in spFactor(). */ - if (Matrix->DoRealDirect == NULL) { - if (( Matrix->DoRealDirect = SP_MALLOC(int, Size+1)) == NULL) +/* Create DoDirect vectors for use in spFactor(). */ +#if REAL + if (Matrix->DoRealDirect == NULL) + { if (( Matrix->DoRealDirect = ALLOC(BOOLEAN, Size+1)) == NULL) Matrix->Error = spNO_MEMORY; } - if (Matrix->DoCmplxDirect == NULL) { - if (( Matrix->DoCmplxDirect = SP_MALLOC(int, Size+1)) == NULL) +#endif +#if spCOMPLEX + if (Matrix->DoCmplxDirect == NULL) + { if (( Matrix->DoCmplxDirect = ALLOC(BOOLEAN, Size+1)) == NULL) Matrix->Error = spNO_MEMORY; } +#endif - /* Create Intermediate vectors for use in MatrixSolve. */ - if (Matrix->Intermediate == NULL) { - if ((Matrix->Intermediate = SP_MALLOC(RealNumber,2*(Size+1))) == NULL) +/* Create Intermediate vectors for use in MatrixSolve. */ +#if spCOMPLEX + if (Matrix->Intermediate == NULL) + { if ((Matrix->Intermediate = ALLOC(RealNumber,2*(Size+1))) == NULL) Matrix->Error = spNO_MEMORY; } +#else + if (Matrix->Intermediate == NULL) + { if ((Matrix->Intermediate = ALLOC(RealNumber, Size+1)) == NULL) + Matrix->Error = spNO_MEMORY; + } +#endif if (Matrix->Error != spNO_MEMORY) Matrix->InternalVectorsAllocated = YES; @@ -802,44 +812,71 @@ spcCreateInternalVectors( MatrixPtr Matrix ) */ static void -CountMarkowitz(MatrixPtr Matrix, RealVector RHS, int Step) +CountMarkowitz( + MatrixPtr Matrix, + register RealVector RHS, + int Step +) { - int Count, I, Size = Matrix->Size; - ElementPtr pElement; - int ExtRow; +register int Count, I, Size = Matrix->Size; +register ElementPtr pElement; +int ExtRow; - /* Begin `CountMarkowitz'. */ +/* Begin `CountMarkowitz'. */ - /* Generate MarkowitzRow Count for each row. */ - for (I = Step; I <= Size; I++) { - /* Set Count to -1 initially to remove count due to pivot element. */ +/* Correct array pointer for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS OR NOT spCOMPLEX + if (RHS != NULL) --RHS; +#else + if (RHS != NULL) + { if (Matrix->Complex) RHS -= 2; + else --RHS; + } +#endif +#endif + +/* Generate MarkowitzRow Count for each row. */ + for (I = Step; I <= Size; I++) + { +/* Set Count to -1 initially to remove count due to pivot element. */ Count = -1; pElement = Matrix->FirstInRow[I]; - while (pElement != NULL && pElement->Col < Step) + while (pElement != NULL AND pElement->Col < Step) pElement = pElement->NextInRow; - while (pElement != NULL) { - Count++; + while (pElement != NULL) + { Count++; pElement = pElement->NextInRow; } - /* Include nonzero elements in the RHS vector. */ +/* Include nonzero elements in the RHS vector. */ ExtRow = Matrix->IntToExtRowMap[I]; +#if spSEPARATED_COMPLEX_VECTORS OR NOT spCOMPLEX if (RHS != NULL) - if (RHS[ExtRow] != 0.0) - Count++; + if (RHS[ExtRow] != 0.0) Count++; +#else + if (RHS != NULL) + { if (Matrix->Complex) + { if ((RHS[2*ExtRow] != 0.0) OR (RHS[2*ExtRow+1] != 0.0)) + Count++; + } + else if (RHS[I] != 0.0) Count++; + } +#endif Matrix->MarkowitzRow[I] = Count; } - /* Generate the MarkowitzCol count for each column. */ - for (I = Step; I <= Size; I++) { - /* Set Count to -1 initially to remove count due to pivot element. */ +/* Generate the MarkowitzCol count for each column. */ + for (I = Step; I <= Size; I++) + { +/* Set Count to -1 initially to remove count due to pivot element. */ Count = -1; pElement = Matrix->FirstInCol[I]; - while (pElement != NULL && pElement->Row < Step) + while (pElement != NULL AND pElement->Row < Step) pElement = pElement->NextInCol; - while (pElement != NULL) { - Count++; + while (pElement != NULL) + { Count++; pElement = pElement->NextInCol; } Matrix->MarkowitzCol[I] = Count; @@ -885,31 +922,36 @@ CountMarkowitz(MatrixPtr Matrix, RealVector RHS, int Step) */ static void -MarkowitzProducts(MatrixPtr Matrix, int Step) +MarkowitzProducts( + MatrixPtr Matrix, + int Step +) { - int I, *pMarkowitzRow, *pMarkowitzCol; - long Product, *pMarkowitzProduct; - int Size = Matrix->Size; - double fProduct; +register int I, *pMarkowitzRow, *pMarkowitzCol; +register long Product, *pMarkowitzProduct; +register int Size = Matrix->Size; +double fProduct; - /* Begin `MarkowitzProducts'. */ +/* Begin `MarkowitzProducts'. */ Matrix->Singletons = 0; pMarkowitzProduct = &(Matrix->MarkowitzProd[Step]); pMarkowitzRow = &(Matrix->MarkowitzRow[Step]); pMarkowitzCol = &(Matrix->MarkowitzCol[Step]); - for (I = Step; I <= Size; I++) { - /* If chance of overflow, use real numbers. */ - if ((*pMarkowitzRow > LARGEST_SHORT_INTEGER && *pMarkowitzCol != 0) || - (*pMarkowitzCol > LARGEST_SHORT_INTEGER && *pMarkowitzRow != 0)) { - fProduct = (double)(*pMarkowitzRow++) * (double)(*pMarkowitzCol++); + for (I = Step; I <= Size; I++) + { +/* If chance of overflow, use real numbers. */ + if ((*pMarkowitzRow > LARGEST_SHORT_INTEGER AND *pMarkowitzCol != 0) OR + (*pMarkowitzCol > LARGEST_SHORT_INTEGER AND *pMarkowitzRow != 0)) + { fProduct = (double)(*pMarkowitzRow++) * (double)(*pMarkowitzCol++); if (fProduct >= LARGEST_LONG_INTEGER) *pMarkowitzProduct++ = LARGEST_LONG_INTEGER; else *pMarkowitzProduct++ = (long)fProduct; - } else { - Product = *pMarkowitzRow++ * *pMarkowitzCol++; + } + else + { Product = *pMarkowitzRow++ * *pMarkowitzCol++; if ((*pMarkowitzProduct++ = Product) == 0) Matrix->Singletons++; } @@ -967,48 +1009,57 @@ MarkowitzProducts(MatrixPtr Matrix, int Step) */ static ElementPtr -SearchForPivot( MatrixPtr Matrix, int Step, int DiagPivoting ) +SearchForPivot( + MatrixPtr Matrix, + int Step, + BOOLEAN DiagPivoting +) { - ElementPtr ChosenPivot; +register ElementPtr ChosenPivot; +ElementPtr SearchForSingleton(); +ElementPtr QuicklySearchDiagonal(); +ElementPtr SearchDiagonal(); +ElementPtr SearchEntireMatrix(); - /* Begin `SearchForPivot'. */ +/* Begin `SearchForPivot'. */ - /* If singletons exist, look for an acceptable one to use as pivot. */ - if (Matrix->Singletons) { - ChosenPivot = SearchForSingleton( Matrix, Step ); - if (ChosenPivot != NULL) { - Matrix->PivotSelectionMethod = 's'; +/* If singletons exist, look for an acceptable one to use as pivot. */ + if (Matrix->Singletons) + { ChosenPivot = SearchForSingleton( Matrix, Step ); + if (ChosenPivot != NULL) + { Matrix->PivotSelectionMethod = 's'; return ChosenPivot; } } #if DIAGONAL_PIVOTING - if (DiagPivoting) { - /* - * Either no singletons exist or they weren't acceptable. Take quick first - * pass at searching diagonal. First search for element on diagonal of - * remaining submatrix with smallest Markowitz product, then check to see - * if it okay numerically. If not, QuicklySearchDiagonal fails. - */ + if (DiagPivoting) + { +/* + * Either no singletons exist or they weren't acceptable. Take quick first + * pass at searching diagonal. First search for element on diagonal of + * remaining submatrix with smallest Markowitz product, then check to see + * if it okay numerically. If not, QuicklySearchDiagonal fails. + */ ChosenPivot = QuicklySearchDiagonal( Matrix, Step ); - if (ChosenPivot != NULL) { - Matrix->PivotSelectionMethod = 'q'; + if (ChosenPivot != NULL) + { Matrix->PivotSelectionMethod = 'q'; return ChosenPivot; } - /* - * Quick search of diagonal failed, carefully search diagonal and check each - * pivot candidate numerically before even tentatively accepting it. - */ +/* + * Quick search of diagonal failed, carefully search diagonal and check each + * pivot candidate numerically before even tentatively accepting it. + */ ChosenPivot = SearchDiagonal( Matrix, Step ); - if (ChosenPivot != NULL) { - Matrix->PivotSelectionMethod = 'd'; + if (ChosenPivot != NULL) + { Matrix->PivotSelectionMethod = 'd'; return ChosenPivot; } } #endif /* DIAGONAL_PIVOTING */ - /* No acceptable pivot found yet, search entire matrix. */ +/* No acceptable pivot found yet, search entire matrix. */ ChosenPivot = SearchEntireMatrix( Matrix, Step ); Matrix->PivotSelectionMethod = 'e'; @@ -1060,135 +1111,143 @@ SearchForPivot( MatrixPtr Matrix, int Step, int DiagPivoting ) */ static ElementPtr -SearchForSingleton( MatrixPtr Matrix, int Step ) +SearchForSingleton( + MatrixPtr Matrix, + int Step +) { - ElementPtr ChosenPivot; - int I; - long *pMarkowitzProduct; - int Singletons; - RealNumber PivotMag; +register ElementPtr ChosenPivot; +register int I; +register long *pMarkowitzProduct; +int Singletons; +RealNumber PivotMag, FindBiggestInColExclude(); - /* Begin `SearchForSingleton'. */ - /* Initialize pointer that is to scan through MarkowitzProduct vector. */ +/* Begin `SearchForSingleton'. */ +/* Initialize pointer that is to scan through MarkowitzProduct vector. */ pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+1]); Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step]; - /* Decrement the count of available singletons, on the assumption that an - * acceptable one will be found. */ +/* Decrement the count of available singletons, on the assumption that an + * acceptable one will be found. */ Singletons = Matrix->Singletons--; - /* - * Assure that following while loop will always terminate, this is just - * preventive medicine, if things are working right this should never - * be needed. - */ +/* + * Assure that following while loop will always terminate, this is just + * preventive medicine, if things are working right this should never + * be needed. + */ Matrix->MarkowitzProd[Step-1] = 0; - while (Singletons-- > 0) { - /* Singletons exist, find them. */ + while (Singletons-- > 0) + { +/* Singletons exist, find them. */ - /* - * This is tricky. Am using a pointer to sequentially step through the - * MarkowitzProduct array. Search terminates when singleton (Product = 0) - * is found. Note that the conditional in the while statement - * ( *pMarkowitzProduct ) is TRUE as long as the MarkowitzProduct is not - * equal to zero. The row (and column)strchr on the diagonal is then - * calculated by subtracting the pointer to the Markowitz product of - * the first diagonal from the pointer to the Markowitz product of the - * desired element, the singleton. - * - * Search proceeds from the end (high row and column numbers) to the - * beginning (low row and column numbers) so that rows and columns with - * large Markowitz products will tend to be move to the bottom of the - * matrix. However, choosing Diag[Step] is desirable because it would - * require no row and column interchanges, so inspect it first by - * putting its Markowitz product at the end of the MarkowitzProd - * vector. - */ +/* + * This is tricky. Am using a pointer to sequentially step through the + * MarkowitzProduct array. Search terminates when singleton (Product = 0) + * is found. Note that the conditional in the while statement + * ( *pMarkowitzProduct ) is true as long as the MarkowitzProduct is not + * equal to zero. The row (and column) index on the diagonal is then + * calculated by subtracting the pointer to the Markowitz product of + * the first diagonal from the pointer to the Markowitz product of the + * desired element, the singleton. + * + * Search proceeds from the end (high row and column numbers) to the + * beginning (low row and column numbers) so that rows and columns with + * large Markowitz products will tend to be move to the bottom of the + * matrix. However, choosing Diag[Step] is desirable because it would + * require no row and column interchanges, so inspect it first by + * putting its Markowitz product at the end of the MarkowitzProd + * vector. + */ - while ( *pMarkowitzProduct-- ) { - /* - * N bottles of beer on the wall; - * N bottles of beer. - * you take one down and pass it around; - * N-1 bottles of beer on the wall. - */ + while ( *pMarkowitzProduct-- ) + { /* + * N bottles of beer on the wall; + * N bottles of beer. + * you take one down and pass it around; + * N-1 bottles of beer on the wall. + */ } - I = (int)(pMarkowitzProduct - Matrix->MarkowitzProd) + 1; + I = pMarkowitzProduct - Matrix->MarkowitzProd + 1; - /* Assure that I is valid. */ +/* Assure that I is valid. */ if (I < Step) break; /* while (Singletons-- > 0) */ if (I > Matrix->Size) I = Step; - /* Singleton has been found in either/both row or/and column I. */ - if ((ChosenPivot = Matrix->Diag[I]) != NULL) { - /* Singleton lies on the diagonal. */ +/* Singleton has been found in either/both row or/and column I. */ + if ((ChosenPivot = Matrix->Diag[I]) != NULL) + { +/* Singleton lies on the diagonal. */ PivotMag = ELEMENT_MAG(ChosenPivot); if - ( PivotMag > Matrix->AbsThreshold && - PivotMag > Matrix->RelThreshold * - FindBiggestInColExclude( Matrix, ChosenPivot, Step ) + ( PivotMag > Matrix->AbsThreshold AND + PivotMag > Matrix->RelThreshold * + FindBiggestInColExclude( Matrix, ChosenPivot, Step ) ) return ChosenPivot; - } else { - /* Singleton does not lie on diagonal, find it. */ - if (Matrix->MarkowitzCol[I] == 0) { - ChosenPivot = Matrix->FirstInCol[I]; - while ((ChosenPivot != NULL) && (ChosenPivot->Row < Step)) + } + else + { +/* Singleton does not lie on diagonal, find it. */ + if (Matrix->MarkowitzCol[I] == 0) + { ChosenPivot = Matrix->FirstInCol[I]; + while ((ChosenPivot != NULL) AND (ChosenPivot->Row < Step)) ChosenPivot = ChosenPivot->NextInCol; - if (ChosenPivot != NULL) { - /* Reduced column has no elements, matrix is singular. */ - break; - } - PivotMag = ELEMENT_MAG(ChosenPivot); + if (ChosenPivot == NULL) + { /* Reduced column has no elements, matrix is singular. */ + break; + } + PivotMag = ELEMENT_MAG( ChosenPivot ); if - ( PivotMag > Matrix->AbsThreshold && - PivotMag > Matrix->RelThreshold * - FindBiggestInColExclude( Matrix, ChosenPivot, - Step ) + ( PivotMag > Matrix->AbsThreshold AND + PivotMag > Matrix->RelThreshold * + FindBiggestInColExclude( Matrix, ChosenPivot, + Step ) ) return ChosenPivot; - else { - if (Matrix->MarkowitzRow[I] == 0) { - ChosenPivot = Matrix->FirstInRow[I]; - while((ChosenPivot != NULL) && (ChosenPivot->ColMarkowitzRow[I] == 0) + { ChosenPivot = Matrix->FirstInRow[I]; + while((ChosenPivot != NULL) AND (ChosenPivot->ColNextInRow; - if (ChosenPivot != NULL) { - /* Reduced row has no elements, matrix is singular. */ - break; - } + if (ChosenPivot == NULL) + {/* Reduced row has no elements, matrix is singular. */ + break; + } PivotMag = ELEMENT_MAG(ChosenPivot); if - ( PivotMag > Matrix->AbsThreshold && - PivotMag > Matrix->RelThreshold * - FindBiggestInColExclude( Matrix, - ChosenPivot, - Step ) + ( PivotMag > Matrix->AbsThreshold AND + PivotMag > Matrix->RelThreshold * + FindBiggestInColExclude( Matrix, + ChosenPivot, + Step ) ) return ChosenPivot; } } - } else { - ChosenPivot = Matrix->FirstInRow[I]; - while ((ChosenPivot != NULL) && (ChosenPivot->Col < Step)) + } + else + { ChosenPivot = Matrix->FirstInRow[I]; + while ((ChosenPivot != NULL) AND (ChosenPivot->Col < Step)) ChosenPivot = ChosenPivot->NextInRow; - if (ChosenPivot != NULL) { - /* Reduced row has no elements, matrix is singular. */ - break; - } + if (ChosenPivot == NULL) + { /* Reduced row has no elements, matrix is singular. */ + break; + } PivotMag = ELEMENT_MAG(ChosenPivot); if - ( PivotMag > Matrix->AbsThreshold && - PivotMag > Matrix->RelThreshold * - FindBiggestInColExclude( Matrix, ChosenPivot, - Step ) + ( PivotMag > Matrix->AbsThreshold AND + PivotMag > Matrix->RelThreshold * + FindBiggestInColExclude( Matrix, ChosenPivot, + Step ) ) return ChosenPivot; } } - /* Singleton not acceptable (too small), try another. */ +/* Singleton not acceptable (too small), try another. */ } /* end of while(lSingletons>0) */ - /* - * All singletons were unacceptable. Restore Matrix->Singletons count. - * Initial assumption that an acceptable singleton would be found was wrong. - */ +/* + * All singletons were unacceptable. Restore Matrix->Singletons count. + * Initial assumption that an acceptable singleton would be found was wrong. + */ Matrix->Singletons++; return NULL; } @@ -1274,57 +1333,60 @@ SearchForSingleton( MatrixPtr Matrix, int Step ) */ static ElementPtr -QuicklySearchDiagonal( MatrixPtr Matrix, int Step ) +QuicklySearchDiagonal( + MatrixPtr Matrix, + int Step +) { - long MinMarkowitzProduct, *pMarkowitzProduct; - ElementPtr pDiag, pOtherInRow, pOtherInCol; - int I, NumberOfTies; - ElementPtr ChosenPivot, TiedElements[MAX_MARKOWITZ_TIES + 1]; - RealNumber Magnitude, LargestInCol, Ratio, MaxRatio; - RealNumber LargestOffDiagonal; - RealNumber FindBiggestInColExclude(); +register long MinMarkowitzProduct, *pMarkowitzProduct; +register ElementPtr pDiag, pOtherInRow, pOtherInCol; +int I, NumberOfTies; +ElementPtr ChosenPivot, TiedElements[MAX_MARKOWITZ_TIES + 1]; +RealNumber Magnitude, LargestInCol, Ratio, MaxRatio; +RealNumber LargestOffDiagonal; +RealNumber FindBiggestInColExclude(); - /* Begin `QuicklySearchDiagonal'. */ +/* Begin `QuicklySearchDiagonal'. */ NumberOfTies = -1; MinMarkowitzProduct = LARGEST_LONG_INTEGER; pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+2]); Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step]; - /* Assure that following while loop will always terminate. */ +/* Assure that following while loop will always terminate. */ Matrix->MarkowitzProd[Step-1] = -1; - /* - * This is tricky. Am using a pointer in the inner while loop to - * sequentially step through the MarkowitzProduct array. Search - * terminates when the Markowitz product of zero placed at location - * Step-1 is found. The row (and column)strchr on the diagonal is then - * calculated by subtracting the pointer to the Markowitz product of - * the first diagonal from the pointer to the Markowitz product of the - * desired element. The outer for loop is infinite, broken by using - * break. - * - * Search proceeds from the end (high row and column numbers) to the - * beginning (low row and column numbers) so that rows and columns with - * large Markowitz products will tend to be move to the bottom of the - * matrix. However, choosing Diag[Step] is desirable because it would - * require no row and column interchanges, so inspect it first by - * putting its Markowitz product at the end of the MarkowitzProd - * vector. - */ +/* + * This is tricky. Am using a pointer in the inner while loop to + * sequentially step through the MarkowitzProduct array. Search + * terminates when the Markowitz product of zero placed at location + * Step-1 is found. The row (and column) index on the diagonal is then + * calculated by subtracting the pointer to the Markowitz product of + * the first diagonal from the pointer to the Markowitz product of the + * desired element. The outer for loop is infinite, broken by using + * break. + * + * Search proceeds from the end (high row and column numbers) to the + * beginning (low row and column numbers) so that rows and columns with + * large Markowitz products will tend to be move to the bottom of the + * matrix. However, choosing Diag[Step] is desirable because it would + * require no row and column interchanges, so inspect it first by + * putting its Markowitz product at the end of the MarkowitzProd + * vector. + */ - for(;;) { /* Endless for loop. */ - while (MinMarkowitzProduct < *(--pMarkowitzProduct)) { - /* - * N bottles of beer on the wall; - * N bottles of beer. - * You take one down and pass it around; - * N-1 bottles of beer on the wall. - */ + for(;;) /* Endless for loop. */ + { while (MinMarkowitzProduct < *(--pMarkowitzProduct)) + { /* + * N bottles of beer on the wall; + * N bottles of beer. + * You take one down and pass it around; + * N-1 bottles of beer on the wall. + */ } I = pMarkowitzProduct - Matrix->MarkowitzProd; - /* Assure that I is valid; if I < Step, terminate search. */ +/* Assure that I is valid; if I < Step, terminate search. */ if (I < Step) break; /* Endless for loop */ if (I > Matrix->Size) I = Step; @@ -1333,71 +1395,76 @@ QuicklySearchDiagonal( MatrixPtr Matrix, int Step ) if ((Magnitude = ELEMENT_MAG(pDiag)) <= Matrix->AbsThreshold) continue; /* Endless for loop */ - if (*pMarkowitzProduct == 1) { - /* Case where only one element exists in row and column other than diagonal. */ + if (*pMarkowitzProduct == 1) + { +/* Case where only one element exists in row and column other than diagonal. */ - /* Find off diagonal elements. */ +/* Find off diagonal elements. */ pOtherInRow = pDiag->NextInRow; pOtherInCol = pDiag->NextInCol; - if (pOtherInRow == NULL && pOtherInCol == NULL) { - pOtherInRow = Matrix->FirstInRow[I]; - while(pOtherInRow != NULL) { - if (pOtherInRow->Col >= Step && pOtherInRow->Col != I) - break; - pOtherInRow = pOtherInRow->NextInRow; - } - pOtherInCol = Matrix->FirstInCol[I]; - while(pOtherInCol != NULL) { - if (pOtherInCol->Row >= Step && pOtherInCol->Row != I) - break; - pOtherInCol = pOtherInCol->NextInCol; - } + if (pOtherInRow == NULL AND pOtherInCol == NULL) + { pOtherInRow = Matrix->FirstInRow[I]; + while(pOtherInRow != NULL) + { if (pOtherInRow->Col >= Step AND pOtherInRow->Col != I) + break; + pOtherInRow = pOtherInRow->NextInRow; + } + pOtherInCol = Matrix->FirstInCol[I]; + while(pOtherInCol != NULL) + { if (pOtherInCol->Row >= Step AND pOtherInCol->Row != I) + break; + pOtherInCol = pOtherInCol->NextInCol; + } } - /* Accept diagonal as pivot if diagonal is larger than off diagonals and the - * off diagonals are placed symmetricly. */ - if (pOtherInRow != NULL && pOtherInCol != NULL) { - if (pOtherInRow->Col == pOtherInCol->Row) { - LargestOffDiagonal = MAX(ELEMENT_MAG(pOtherInRow), - ELEMENT_MAG(pOtherInCol)); - if (Magnitude >= LargestOffDiagonal) { - /* Accept pivot, it is unlikely to contribute excess error. */ +/* Accept diagonal as pivot if diagonal is larger than off diagonals and the + * off diagonals are placed symmetricly. */ + if (pOtherInRow != NULL AND pOtherInCol != NULL) + { if (pOtherInRow->Col == pOtherInCol->Row) + { LargestOffDiagonal = MAX(ELEMENT_MAG(pOtherInRow), + ELEMENT_MAG(pOtherInCol)); + if (Magnitude >= LargestOffDiagonal) + { +/* Accept pivot, it is unlikely to contribute excess error. */ return pDiag; } } } } - if (*pMarkowitzProduct < MinMarkowitzProduct) { - /* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */ + if (*pMarkowitzProduct < MinMarkowitzProduct) + { +/* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */ TiedElements[0] = pDiag; MinMarkowitzProduct = *pMarkowitzProduct; NumberOfTies = 0; - } else { - /* This case handles Markowitz ties. */ - if (NumberOfTies < MAX_MARKOWITZ_TIES) { - TiedElements[++NumberOfTies] = pDiag; + } + else + { +/* This case handles Markowitz ties. */ + if (NumberOfTies < MAX_MARKOWITZ_TIES) + { TiedElements[++NumberOfTies] = pDiag; if (NumberOfTies >= MinMarkowitzProduct * TIES_MULTIPLIER) break; /* Endless for loop */ } } } /* End of endless for loop. */ - /* Test to see if any element was chosen as a pivot candidate. */ +/* Test to see if any element was chosen as a pivot candidate. */ if (NumberOfTies < 0) return NULL; - /* Determine which of tied elements is best numerically. */ +/* Determine which of tied elements is best numerically. */ ChosenPivot = NULL; MaxRatio = 1.0 / Matrix->RelThreshold; - for (I = 0; I <= NumberOfTies; I++) { - pDiag = TiedElements[I]; + for (I = 0; I <= NumberOfTies; I++) + { pDiag = TiedElements[I]; Magnitude = ELEMENT_MAG(pDiag); LargestInCol = FindBiggestInColExclude( Matrix, pDiag, Step ); Ratio = LargestInCol / Magnitude; - if (Ratio < MaxRatio) { - ChosenPivot = pDiag; + if (Ratio < MaxRatio) + { ChosenPivot = pDiag; MaxRatio = Ratio; } } @@ -1465,50 +1532,54 @@ QuicklySearchDiagonal( MatrixPtr Matrix, int Step ) */ static ElementPtr -QuicklySearchDiagonal( MatrixPtr Matrix, int Step ) +QuicklySearchDiagonal( + MatrixPtr Matrix, + int Step +) { - long MinMarkowitzProduct, *pMarkowitzProduct; - ElementPtr pDiag; - int I; - ElementPtr ChosenPivot, pOtherInRow, pOtherInCol; - RealNumber Magnitude, LargestInCol, LargestOffDiagonal; +register long MinMarkowitzProduct, *pMarkowitzProduct; +register ElementPtr pDiag; +int I; +ElementPtr ChosenPivot, pOtherInRow, pOtherInCol; +RealNumber Magnitude, LargestInCol, LargestOffDiagonal; +RealNumber FindBiggestInColExclude(); - /* Begin `QuicklySearchDiagonal'. */ +/* Begin `QuicklySearchDiagonal'. */ ChosenPivot = NULL; MinMarkowitzProduct = LARGEST_LONG_INTEGER; pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+2]); Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step]; - /* Assure that following while loop will always terminate. */ +/* Assure that following while loop will always terminate. */ Matrix->MarkowitzProd[Step-1] = -1; - /* - * This is tricky. Am using a pointer in the inner while loop to - * sequentially step through the MarkowitzProduct array. Search - * terminates when the Markowitz product of zero placed at location - * Step-1 is found. The row (and column)strchr on the diagonal is then - * calculated by subtracting the pointer to the Markowitz product of - * the first diagonal from the pointer to the Markowitz product of the - * desired element. The outer for loop is infinite, broken by using - * break. - * - * Search proceeds from the end (high row and column numbers) to the - * beginning (low row and column numbers) so that rows and columns with - * large Markowitz products will tend to be move to the bottom of the - * matrix. However, choosing Diag[Step] is desirable because it would - * require no row and column interchanges, so inspect it first by - * putting its Markowitz product at the end of the MarkowitzProd - * vector. - */ +/* + * This is tricky. Am using a pointer in the inner while loop to + * sequentially step through the MarkowitzProduct array. Search + * terminates when the Markowitz product of zero placed at location + * Step-1 is found. The row (and column) index on the diagonal is then + * calculated by subtracting the pointer to the Markowitz product of + * the first diagonal from the pointer to the Markowitz product of the + * desired element. The outer for loop is infinite, broken by using + * break. + * + * Search proceeds from the end (high row and column numbers) to the + * beginning (low row and column numbers) so that rows and columns with + * large Markowitz products will tend to be move to the bottom of the + * matrix. However, choosing Diag[Step] is desirable because it would + * require no row and column interchanges, so inspect it first by + * putting its Markowitz product at the end of the MarkowitzProd + * vector. + */ - for (;;) { /* Endless for loop. */ - while (*(--pMarkowitzProduct) >= MinMarkowitzProduct) { - /* Just passing through. */ + for (;;) /* Endless for loop. */ + { while (*(--pMarkowitzProduct) >= MinMarkowitzProduct) + { /* Just passing through. */ } - I = (int)(pMarkowitzProduct - Matrix->MarkowitzProd); + I = pMarkowitzProduct - Matrix->MarkowitzProd; - /* Assure that I is valid; if I < Step, terminate search. */ +/* Assure that I is valid; if I < Step, terminate search. */ if (I < Step) break; /* Endless for loop */ if (I > Matrix->Size) I = Step; @@ -1517,35 +1588,37 @@ QuicklySearchDiagonal( MatrixPtr Matrix, int Step ) if ((Magnitude = ELEMENT_MAG(pDiag)) <= Matrix->AbsThreshold) continue; /* Endless for loop */ - if (*pMarkowitzProduct == 1) { - /* Case where only one element exists in row and column other than diagonal. */ + if (*pMarkowitzProduct == 1) + { +/* Case where only one element exists in row and column other than diagonal. */ - /* Find off-diagonal elements. */ +/* Find off-diagonal elements. */ pOtherInRow = pDiag->NextInRow; pOtherInCol = pDiag->NextInCol; - if (pOtherInRow == NULL && pOtherInCol == NULL) { - pOtherInRow = Matrix->FirstInRow[I]; - while(pOtherInRow != NULL) { - if (pOtherInRow->Col >= Step && pOtherInRow->Col != I) - break; - pOtherInRow = pOtherInRow->NextInRow; - } - pOtherInCol = Matrix->FirstInCol[I]; - while(pOtherInCol != NULL) { - if (pOtherInCol->Row >= Step && pOtherInCol->Row != I) - break; - pOtherInCol = pOtherInCol->NextInCol; - } + if (pOtherInRow == NULL AND pOtherInCol == NULL) + { pOtherInRow = Matrix->FirstInRow[I]; + while(pOtherInRow != NULL) + { if (pOtherInRow->Col >= Step AND pOtherInRow->Col != I) + break; + pOtherInRow = pOtherInRow->NextInRow; + } + pOtherInCol = Matrix->FirstInCol[I]; + while(pOtherInCol != NULL) + { if (pOtherInCol->Row >= Step AND pOtherInCol->Row != I) + break; + pOtherInCol = pOtherInCol->NextInCol; + } } - /* Accept diagonal as pivot if diagonal is larger than off-diagonals and the - * off-diagonals are placed symmetricly. */ - if (pOtherInRow != NULL && pOtherInCol != NULL) { - if (pOtherInRow->Col == pOtherInCol->Row) { - LargestOffDiagonal = MAX(ELEMENT_MAG(pOtherInRow), - ELEMENT_MAG(pOtherInCol)); - if (Magnitude >= LargestOffDiagonal) { - /* Accept pivot, it is unlikely to contribute excess error. */ +/* Accept diagonal as pivot if diagonal is larger than off-diagonals and the + * off-diagonals are placed symmetricly. */ + if (pOtherInRow != NULL AND pOtherInCol != NULL) + { if (pOtherInRow->Col == pOtherInCol->Row) + { LargestOffDiagonal = MAX(ELEMENT_MAG(pOtherInRow), + ELEMENT_MAG(pOtherInCol)); + if (Magnitude >= LargestOffDiagonal) + { +/* Accept pivot, it is unlikely to contribute excess error. */ return pDiag; } } @@ -1556,8 +1629,8 @@ QuicklySearchDiagonal( MatrixPtr Matrix, int Step ) ChosenPivot = pDiag; } /* End of endless for loop. */ - if (ChosenPivot != NULL) { - LargestInCol = FindBiggestInColExclude( Matrix, ChosenPivot, Step ); + if (ChosenPivot != NULL) + { LargestInCol = FindBiggestInColExclude( Matrix, ChosenPivot, Step ); if( ELEMENT_MAG(ChosenPivot) <= Matrix->RelThreshold * LargestInCol ) ChosenPivot = NULL; } @@ -1601,7 +1674,7 @@ QuicklySearchDiagonal( MatrixPtr Matrix, int Step ) * ChosenPivot (ElementPtr) * Pointer to the element that has been chosen to be the pivot. * Size (int) - * Local version of size which is placed in a to increase speed. + * Local version of size which is placed in a register to increase speed. * Magnitude (RealNumber) * Absolute value of diagonal element. * MinMarkowitzProduct (long) @@ -1624,28 +1697,29 @@ QuicklySearchDiagonal( MatrixPtr Matrix, int Step ) */ static ElementPtr -SearchDiagonal( MatrixPtr Matrix, int Step ) +SearchDiagonal( + MatrixPtr Matrix, + register int Step +) { - int J; - long MinMarkowitzProduct, *pMarkowitzProduct; - int I; - ElementPtr pDiag; - int NumberOfTies = 0; - int Size = Matrix->Size; +register int J; +register long MinMarkowitzProduct, *pMarkowitzProduct; +register int I; +register ElementPtr pDiag; +int NumberOfTies = 0, Size = Matrix->Size; +ElementPtr ChosenPivot; +RealNumber Magnitude, Ratio, RatioOfAccepted = 0, LargestInCol; +RealNumber FindBiggestInColExclude(); - ElementPtr ChosenPivot; - RealNumber Magnitude, Ratio; - RealNumber RatioOfAccepted = 0; - RealNumber LargestInCol; - - /* Begin `SearchDiagonal'. */ +/* Begin `SearchDiagonal'. */ ChosenPivot = NULL; MinMarkowitzProduct = LARGEST_LONG_INTEGER; pMarkowitzProduct = &(Matrix->MarkowitzProd[Size+2]); Matrix->MarkowitzProd[Size+1] = Matrix->MarkowitzProd[Step]; - /* Start search of diagonal. */ - for (J = Size+1; J > Step; J--) { +/* Start search of diagonal. */ + for (J = Size+1; J > Step; J--) + { if (*(--pMarkowitzProduct) > MinMarkowitzProduct) continue; /* for loop */ if (J > Matrix->Size) @@ -1657,24 +1731,26 @@ SearchDiagonal( MatrixPtr Matrix, int Step ) if ((Magnitude = ELEMENT_MAG(pDiag)) <= Matrix->AbsThreshold) continue; /* for loop */ - /* Test to see if diagonal's magnitude is acceptable. */ +/* Test to see if diagonal's magnitude is acceptable. */ LargestInCol = FindBiggestInColExclude( Matrix, pDiag, Step ); if (Magnitude <= Matrix->RelThreshold * LargestInCol) continue; /* for loop */ - if (*pMarkowitzProduct < MinMarkowitzProduct) { - /* Notice strict inequality in test. This is a new - smallest MarkowitzProduct. */ + if (*pMarkowitzProduct < MinMarkowitzProduct) + { +/* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */ ChosenPivot = pDiag; MinMarkowitzProduct = *pMarkowitzProduct; RatioOfAccepted = LargestInCol / Magnitude; NumberOfTies = 0; - } else { - /* This case handles Markowitz ties. */ + } + else + { +/* This case handles Markowitz ties. */ NumberOfTies++; Ratio = LargestInCol / Magnitude; - if (Ratio < RatioOfAccepted) { - ChosenPivot = pDiag; + if (Ratio < RatioOfAccepted) + { ChosenPivot = pDiag; RatioOfAccepted = Ratio; } if (NumberOfTies >= MinMarkowitzProduct * TIES_MULTIPLIER) @@ -1722,7 +1798,7 @@ SearchDiagonal( MatrixPtr Matrix, int Step ) * LargestElementMag (RealNumber) * Magnitude of the largest element yet found in the reduced submatrix. * Size (int) - * Local version of Size; placed in a for speed. + * Local version of Size; placed in a register for speed. * Magnitude (RealNumber) * Absolute value of diagonal element. * MinMarkowitzProduct (long) @@ -1750,65 +1826,68 @@ SearchDiagonal( MatrixPtr Matrix, int Step ) */ static ElementPtr -SearchEntireMatrix( MatrixPtr Matrix, int Step ) +SearchEntireMatrix( + MatrixPtr Matrix, + int Step +) { - int I, Size = Matrix->Size; - ElementPtr pElement; - int NumberOfTies = 0; - long Product, MinMarkowitzProduct; - ElementPtr ChosenPivot; - ElementPtr pLargestElement = NULL; - RealNumber Magnitude, LargestElementMag, Ratio; - RealNumber RatioOfAccepted = 0; - RealNumber LargestInCol; +register int I, Size = Matrix->Size; +register ElementPtr pElement; +int NumberOfTies = 0; +long Product, MinMarkowitzProduct; +ElementPtr ChosenPivot, pLargestElement; +RealNumber Magnitude, LargestElementMag, Ratio, RatioOfAccepted = 0, LargestInCol; +RealNumber FindLargestInCol(); - /* Begin `SearchEntireMatrix'. */ +/* Begin `SearchEntireMatrix'. */ ChosenPivot = NULL; LargestElementMag = 0.0; MinMarkowitzProduct = LARGEST_LONG_INTEGER; - /* Start search of matrix on column by column basis. */ - for (I = Step; I <= Size; I++) { - pElement = Matrix->FirstInCol[I]; +/* Start search of matrix on column by column basis. */ + for (I = Step; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; - while (pElement != NULL && pElement->Row < Step) + while (pElement != NULL AND pElement->Row < Step) pElement = pElement->NextInCol; if((LargestInCol = FindLargestInCol(pElement)) == 0.0) continue; /* for loop */ - while (pElement != NULL) { - /* Check to see if element is the largest encountered so - far. If so, record its magnitude and address. */ - if ((Magnitude = ELEMENT_MAG(pElement)) > LargestElementMag) { - LargestElementMag = Magnitude; + while (pElement != NULL) + { +/* Check to see if element is the largest encountered so far. If so, record + its magnitude and address. */ + if ((Magnitude = ELEMENT_MAG(pElement)) > LargestElementMag) + { LargestElementMag = Magnitude; pLargestElement = pElement; } - /* Calculate element's MarkowitzProduct. */ - Product = Matrix->MarkowitzRow[pElement->Row] * - Matrix->MarkowitzCol[pElement->Col]; +/* Calculate element's MarkowitzProduct. */ + spcMarkoProd( Product, Matrix->MarkowitzRow[pElement->Row], + Matrix->MarkowitzCol[pElement->Col] ); - /* Test to see if element is acceptable as a pivot - candidate. */ - if ((Product <= MinMarkowitzProduct) && - (Magnitude > Matrix->RelThreshold * LargestInCol) && - (Magnitude > Matrix->AbsThreshold)) { - /* Test to see if element has lowest MarkowitzProduct - yet found, or whether it is tied with an element - found earlier. */ - if (Product < MinMarkowitzProduct) { - /* Notice strict inequality in test. This is a new - smallest MarkowitzProduct. */ +/* Test to see if element is acceptable as a pivot candidate. */ + if ((Product <= MinMarkowitzProduct) AND + (Magnitude > Matrix->RelThreshold * LargestInCol) AND + (Magnitude > Matrix->AbsThreshold)) + { +/* Test to see if element has lowest MarkowitzProduct yet found, or whether it + is tied with an element found earlier. */ + if (Product < MinMarkowitzProduct) + { +/* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */ ChosenPivot = pElement; MinMarkowitzProduct = Product; RatioOfAccepted = LargestInCol / Magnitude; NumberOfTies = 0; - } else { - /* This case handles Markowitz ties. */ + } + else + { +/* This case handles Markowitz ties. */ NumberOfTies++; Ratio = LargestInCol / Magnitude; - if (Ratio < RatioOfAccepted) { - ChosenPivot = pElement; + if (Ratio < RatioOfAccepted) + { ChosenPivot = pElement; RatioOfAccepted = Ratio; } if (NumberOfTies >= MinMarkowitzProduct * TIES_MULTIPLIER) @@ -1821,8 +1900,8 @@ SearchEntireMatrix( MatrixPtr Matrix, int Step ) if (ChosenPivot != NULL) return ChosenPivot; - if (LargestElementMag == 0.0) { - Matrix->Error = spSINGULAR; + if (LargestElementMag == 0.0) + { Matrix->Error = spSINGULAR; return NULL; } @@ -1844,14 +1923,14 @@ SearchEntireMatrix( MatrixPtr Matrix, int Step ) /* * DETERMINE THE MAGNITUDE OF THE LARGEST ELEMENT IN A COLUMN * - * This routine searches a column and returns the magnitude of the - * largest element. This routine begins the search at the element - * pointed to by pElement, the parameter. + * This routine searches a column and returns the magnitude of the largest + * element. This routine begins the search at the element pointed to by + * pElement, the parameter. * - * The search is conducted by starting at the element specified by a - * pointer, which should be one below the diagonal, and moving down - * the column. On the way down the column, the magnitudes of the - * elements are tested to see if they are the largest yet found. + * The search is conducted by starting at the element specified by a pointer, + * which should be one below the diagonal, and moving down the column. On + * the way down the column, the magnitudes of the elements are tested to see + * if they are the largest yet found. * * >>> Returned: * The magnitude of the largest element in the column below and including @@ -1866,17 +1945,18 @@ SearchEntireMatrix( MatrixPtr Matrix, int Step ) * Largest (RealNumber) * The magnitude of the largest element. * Magnitude (RealNumber) - * The magnitude of the currently active element. */ + * The magnitude of the currently active element. + */ static RealNumber -FindLargestInCol( ElementPtr pElement ) +FindLargestInCol( register ElementPtr pElement ) { - RealNumber Magnitude, Largest = 0.0; +RealNumber Magnitude, Largest = 0.0; - /* Begin `FindLargestInCol'. */ - /* Search column for largest element beginning at Element. */ - while (pElement != NULL) { - if ((Magnitude = ELEMENT_MAG(pElement)) > Largest) +/* Begin `FindLargestInCol'. */ +/* Search column for largest element beginning at Element. */ + while (pElement != NULL) + { if ((Magnitude = ELEMENT_MAG(pElement)) > Largest) Largest = Magnitude; pElement = pElement->NextInCol; } @@ -1933,31 +2013,35 @@ FindLargestInCol( ElementPtr pElement ) */ static RealNumber -FindBiggestInColExclude( MatrixPtr Matrix, ElementPtr pElement, int Step ) +FindBiggestInColExclude( + MatrixPtr Matrix, + register ElementPtr pElement, + register int Step +) { - int Row; - int Col; - RealNumber Largest, Magnitude; +register int Row; +int Col; +RealNumber Largest, Magnitude; - /* Begin `FindBiggestInColExclude'. */ +/* Begin `FindBiggestInColExclude'. */ Row = pElement->Row; Col = pElement->Col; pElement = Matrix->FirstInCol[Col]; - /* Travel down column until reduced submatrix is entered. */ - while ((pElement != NULL) && (pElement->Row < Step)) +/* Travel down column until reduced submatrix is entered. */ + while ((pElement != NULL) AND (pElement->Row < Step)) pElement = pElement->NextInCol; - /* Initialize the variable Largest. */ +/* Initialize the variable Largest. */ if (pElement->Row != Row) Largest = ELEMENT_MAG(pElement); else Largest = 0.0; - /* Search rest of column for largest element, avoiding excluded element. */ - while ((pElement = pElement->NextInCol) != NULL) { - if ((Magnitude = ELEMENT_MAG(pElement)) > Largest) { - if (pElement->Row != Row) +/* Search rest of column for largest element, avoiding excluded element. */ + while ((pElement = pElement->NextInCol) != NULL) + { if ((Magnitude = ELEMENT_MAG(pElement)) > Largest) + { if (pElement->Row != Row) Largest = Magnitude; } } @@ -2006,83 +2090,84 @@ FindBiggestInColExclude( MatrixPtr Matrix, ElementPtr pElement, int Step ) */ static void -ExchangeRowsAndCols( MatrixPtr Matrix, ElementPtr pPivot, int Step ) +ExchangeRowsAndCols( + MatrixPtr Matrix, + ElementPtr pPivot, + register int Step +) { - int Row, Col; - long OldMarkowitzProd_Step, OldMarkowitzProd_Row, OldMarkowitzProd_Col; +register int Row, Col; +long OldMarkowitzProd_Step, OldMarkowitzProd_Row, OldMarkowitzProd_Col; - /* Begin `ExchangeRowsAndCols'. */ +/* Begin `ExchangeRowsAndCols'. */ Row = pPivot->Row; Col = pPivot->Col; Matrix->PivotsOriginalRow = Row; Matrix->PivotsOriginalCol = Col; - if ((Row == Step) && (Col == Step)) return; + if ((Row == Step) AND (Col == Step)) return; - /* Exchange rows and columns. */ - if (Row == Col) { - spcRowExchange( Matrix, Step, Row ); +/* Exchange rows and columns. */ + if (Row == Col) + { spcRowExchange( Matrix, Step, Row ); spcColExchange( Matrix, Step, Col ); SWAP( long, Matrix->MarkowitzProd[Step], Matrix->MarkowitzProd[Row] ); SWAP( ElementPtr, Matrix->Diag[Row], Matrix->Diag[Step] ); - } else { + } + else + { - /* Initialize variables that hold old Markowitz products. */ +/* Initialize variables that hold old Markowitz products. */ OldMarkowitzProd_Step = Matrix->MarkowitzProd[Step]; OldMarkowitzProd_Row = Matrix->MarkowitzProd[Row]; OldMarkowitzProd_Col = Matrix->MarkowitzProd[Col]; - /* Exchange rows. */ - if (Row != Step) { - spcRowExchange( Matrix, Step, Row ); +/* Exchange rows. */ + if (Row != Step) + { spcRowExchange( Matrix, Step, Row ); Matrix->NumberOfInterchangesIsOdd = - !Matrix->NumberOfInterchangesIsOdd; - Matrix->MarkowitzProd[Row] = Matrix->MarkowitzRow[Row] * - Matrix->MarkowitzCol[Row]; + NOT Matrix->NumberOfInterchangesIsOdd; + spcMarkoProd( Matrix->MarkowitzProd[Row], + Matrix->MarkowitzRow[Row], + Matrix->MarkowitzCol[Row] ); - /* Update singleton count. */ - if ((Matrix->MarkowitzProd[Row]==0) != (OldMarkowitzProd_Row==0)) { - if (OldMarkowitzProd_Row == 0) +/* Update singleton count. */ + if ((Matrix->MarkowitzProd[Row]==0) != (OldMarkowitzProd_Row==0)) + { if (OldMarkowitzProd_Row == 0) Matrix->Singletons--; else Matrix->Singletons++; } } - /* Exchange columns. */ - if (Col != Step) { - spcColExchange( Matrix, Step, Col ); +/* Exchange columns. */ + if (Col != Step) + { spcColExchange( Matrix, Step, Col ); Matrix->NumberOfInterchangesIsOdd = - !Matrix->NumberOfInterchangesIsOdd; - Matrix->MarkowitzProd[Col] = Matrix->MarkowitzCol[Col] * - Matrix->MarkowitzRow[Col]; + NOT Matrix->NumberOfInterchangesIsOdd; + spcMarkoProd( Matrix->MarkowitzProd[Col], + Matrix->MarkowitzCol[Col], + Matrix->MarkowitzRow[Col] ); - /* Update singleton count. */ - if ((Matrix->MarkowitzProd[Col]==0) != (OldMarkowitzProd_Col==0)) { - if (OldMarkowitzProd_Col == 0) +/* Update singleton count. */ + if ((Matrix->MarkowitzProd[Col]==0) != (OldMarkowitzProd_Col==0)) + { if (OldMarkowitzProd_Col == 0) Matrix->Singletons--; else Matrix->Singletons++; } - Matrix->Diag[Col] = spcFindElementInCol( Matrix, - Matrix->FirstInCol+Col, - Col, Col, NO ); + Matrix->Diag[Col] = spcFindDiag( Matrix, Col ); } - if (Row != Step) { - Matrix->Diag[Row] = spcFindElementInCol( Matrix, - Matrix->FirstInCol+Row, - Row, Row, NO ); - } - Matrix->Diag[Step] = spcFindElementInCol( Matrix, - Matrix->FirstInCol+Step, - Step, Step, NO ); + if (Row != Step) + Matrix->Diag[Row] = spcFindDiag( Matrix, Row ); + Matrix->Diag[Step] = spcFindDiag( Matrix, Step ); - /* Update singleton count. */ +/* Update singleton count. */ Matrix->MarkowitzProd[Step] = Matrix->MarkowitzCol[Step] * - Matrix->MarkowitzRow[Step]; - if ((Matrix->MarkowitzProd[Step]==0) != (OldMarkowitzProd_Step==0)) { - if (OldMarkowitzProd_Step == 0) + Matrix->MarkowitzRow[Step]; + if ((Matrix->MarkowitzProd[Step]==0) != (OldMarkowitzProd_Step==0)) + { if (OldMarkowitzProd_Step == 0) Matrix->Singletons--; else Matrix->Singletons++; @@ -2104,16 +2189,16 @@ ExchangeRowsAndCols( MatrixPtr Matrix, ElementPtr pPivot, int Step ) * * Performs all required operations to exchange two rows. Those operations * include: swap FirstInRow pointers, fixing up the NextInCol pointers, - * swapping rowstrchres in MatrixElements, and swapping Markowitz row + * swapping row indexes in MatrixElements, and swapping Markowitz row * counts. * * >>> Arguments: * Matrix (MatrixPtr) * Pointer to the matrix. * Row1 (int) - * Rowstrchr of one of the rows, becomes the smalleststrchr. + * Row index of one of the rows, becomes the smallest index. * Row2 (int) - * Rowstrchr of the other row, becomes the largeststrchr. + * Row index of the other row, becomes the largest index. * * Local variables: * Column (int) @@ -2129,41 +2214,50 @@ ExchangeRowsAndCols( MatrixPtr Matrix, ElementPtr pPivot, int Step ) */ void -spcRowExchange( MatrixPtr Matrix, int Row1, int Row2 ) +spcRowExchange( + MatrixPtr Matrix, + int Row1, + int Row2 +) { - ElementPtr Row1Ptr, Row2Ptr; - int Column; - ElementPtr Element1, Element2; +register ElementPtr Row1Ptr, Row2Ptr; +int Column; +ElementPtr Element1, Element2; - /* Begin `spcRowExchange'. */ +/* Begin `spcRowExchange'. */ if (Row1 > Row2) SWAP(int, Row1, Row2); Row1Ptr = Matrix->FirstInRow[Row1]; Row2Ptr = Matrix->FirstInRow[Row2]; - while (Row1Ptr != NULL || Row2Ptr != NULL) { - /* Exchange elements in rows while traveling from left to right. */ - if (Row1Ptr == NULL) { - Column = Row2Ptr->Col; + while (Row1Ptr != NULL OR Row2Ptr != NULL) + { +/* Exchange elements in rows while traveling from left to right. */ + if (Row1Ptr == NULL) + { Column = Row2Ptr->Col; Element1 = NULL; Element2 = Row2Ptr; Row2Ptr = Row2Ptr->NextInRow; - } else if (Row2Ptr == NULL) { - Column = Row1Ptr->Col; + } + else if (Row2Ptr == NULL) + { Column = Row1Ptr->Col; Element1 = Row1Ptr; Element2 = NULL; Row1Ptr = Row1Ptr->NextInRow; - } else if (Row1Ptr->Col < Row2Ptr->Col) { - Column = Row1Ptr->Col; + } + else if (Row1Ptr->Col < Row2Ptr->Col) + { Column = Row1Ptr->Col; Element1 = Row1Ptr; Element2 = NULL; Row1Ptr = Row1Ptr->NextInRow; - } else if (Row1Ptr->Col > Row2Ptr->Col) { - Column = Row2Ptr->Col; + } + else if (Row1Ptr->Col > Row2Ptr->Col) + { Column = Row2Ptr->Col; Element1 = NULL; Element2 = Row2Ptr; Row2Ptr = Row2Ptr->NextInRow; - } else { /* Row1Ptr->Col == Row2Ptr->Col */ - Column = Row1Ptr->Col; + } + else /* Row1Ptr->Col == Row2Ptr->Col */ + { Column = Row1Ptr->Col; Element1 = Row1Ptr; Element2 = Row2Ptr; Row1Ptr = Row1Ptr->NextInRow; @@ -2171,7 +2265,7 @@ spcRowExchange( MatrixPtr Matrix, int Row1, int Row2 ) } ExchangeColElements( Matrix, Row1, Element1, Row2, Element2, Column); - } /* end of while(Row1Ptr != NULL || Row2Ptr != NULL) */ + } /* end of while(Row1Ptr != NULL OR Row2Ptr != NULL) */ if (Matrix->InternalVectorsAllocated) SWAP( int, Matrix->MarkowitzRow[Row1], Matrix->MarkowitzRow[Row2]); @@ -2198,16 +2292,16 @@ spcRowExchange( MatrixPtr Matrix, int Row1, int Row2 ) * * Performs all required operations to exchange two columns. Those operations * include: swap FirstInCol pointers, fixing up the NextInRow pointers, - * swapping columnstrchres in MatrixElements, and swapping Markowitz + * swapping column indexes in MatrixElements, and swapping Markowitz * column counts. * * >>> Arguments: * Matrix (MatrixPtr) * Pointer to the matrix. * Col1 (int) - * Columnstrchr of one of the columns, becomes the smalleststrchr. + * Column index of one of the columns, becomes the smallest index. * Col2 (int) - * Columnstrchr of the other column, becomes the largeststrchr + * Column index of the other column, becomes the largest index * * Local variables: * Row (int) @@ -2223,41 +2317,50 @@ spcRowExchange( MatrixPtr Matrix, int Row1, int Row2 ) */ void -spcColExchange( MatrixPtr Matrix, int Col1, int Col2 ) +spcColExchange( + MatrixPtr Matrix, + int Col1, + int Col2 +) { - ElementPtr Col1Ptr, Col2Ptr; - int Row; - ElementPtr Element1, Element2; +register ElementPtr Col1Ptr, Col2Ptr; +int Row; +ElementPtr Element1, Element2; - /* Begin `spcColExchange'. */ +/* Begin `spcColExchange'. */ if (Col1 > Col2) SWAP(int, Col1, Col2); Col1Ptr = Matrix->FirstInCol[Col1]; Col2Ptr = Matrix->FirstInCol[Col2]; - while (Col1Ptr != NULL || Col2Ptr != NULL) { - /* Exchange elements in rows while traveling from top to bottom. */ - if (Col1Ptr == NULL) { - Row = Col2Ptr->Row; + while (Col1Ptr != NULL OR Col2Ptr != NULL) + { +/* Exchange elements in rows while traveling from top to bottom. */ + if (Col1Ptr == NULL) + { Row = Col2Ptr->Row; Element1 = NULL; Element2 = Col2Ptr; Col2Ptr = Col2Ptr->NextInCol; - } else if (Col2Ptr == NULL) { - Row = Col1Ptr->Row; + } + else if (Col2Ptr == NULL) + { Row = Col1Ptr->Row; Element1 = Col1Ptr; Element2 = NULL; Col1Ptr = Col1Ptr->NextInCol; - } else if (Col1Ptr->Row < Col2Ptr->Row) { - Row = Col1Ptr->Row; + } + else if (Col1Ptr->Row < Col2Ptr->Row) + { Row = Col1Ptr->Row; Element1 = Col1Ptr; Element2 = NULL; Col1Ptr = Col1Ptr->NextInCol; - } else if (Col1Ptr->Row > Col2Ptr->Row) { - Row = Col2Ptr->Row; + } + else if (Col1Ptr->Row > Col2Ptr->Row) + { Row = Col2Ptr->Row; Element1 = NULL; Element2 = Col2Ptr; Col2Ptr = Col2Ptr->NextInCol; - } else { /* Col1Ptr->Row == Col2Ptr->Row */ - Row = Col1Ptr->Row; + } + else /* Col1Ptr->Row == Col2Ptr->Row */ + { Row = Col1Ptr->Row; Element1 = Col1Ptr; Element2 = Col2Ptr; Col1Ptr = Col1Ptr->NextInCol; @@ -2265,7 +2368,7 @@ spcColExchange( MatrixPtr Matrix, int Col1, int Col2 ) } ExchangeRowElements( Matrix, Col1, Element1, Col2, Element2, Row); - } /* end of while(Col1Ptr != NULL || Col2Ptr != NULL) */ + } /* end of while(Col1Ptr != NULL OR Col2Ptr != NULL) */ if (Matrix->InternalVectorsAllocated) SWAP( int, Matrix->MarkowitzCol[Col1], Matrix->MarkowitzCol[Col2]); @@ -2289,7 +2392,7 @@ spcColExchange( MatrixPtr Matrix, int Col1, int Col2 ) * EXCHANGE TWO ELEMENTS IN A COLUMN * * Performs all required operations to exchange two elements in a column. - * Those operations are: restring NextInCol pointers and swapping rowstrchres + * Those operations are: restring NextInCol pointers and swapping row indexes * in the MatrixElements. * * >>> Arguments: @@ -2322,59 +2425,73 @@ spcColExchange( MatrixPtr Matrix, int Col1, int Col2 ) */ static void -ExchangeColElements( MatrixPtr Matrix, int Row1, ElementPtr Element1, int Row2, ElementPtr Element2, int Column ) +ExchangeColElements( + MatrixPtr Matrix, + int Row1, + register ElementPtr Element1, + int Row2, + register ElementPtr Element2, + int Column +) { - ElementPtr *ElementAboveRow1, *ElementAboveRow2; - ElementPtr ElementBelowRow1, ElementBelowRow2; - ElementPtr pElement; +ElementPtr *ElementAboveRow1, *ElementAboveRow2; +ElementPtr ElementBelowRow1, ElementBelowRow2; +register ElementPtr pElement; - /* Begin `ExchangeColElements'. */ - /* Search to find the ElementAboveRow1. */ +/* Begin `ExchangeColElements'. */ +/* Search to find the ElementAboveRow1. */ ElementAboveRow1 = &(Matrix->FirstInCol[Column]); pElement = *ElementAboveRow1; - while (pElement->Row < Row1) { - ElementAboveRow1 = &(pElement->NextInCol); + while (pElement->Row < Row1) + { ElementAboveRow1 = &(pElement->NextInCol); pElement = *ElementAboveRow1; } - if (Element1 != NULL) { - ElementBelowRow1 = Element1->NextInCol; - if (Element2 == NULL) { - /* Element2 does not exist, move Element1 down to Row2. */ - if ( ElementBelowRow1 != NULL && ElementBelowRow1->Row < Row2 ) { - /* Element1 must be removed from linked list and moved. */ + if (Element1 != NULL) + { ElementBelowRow1 = Element1->NextInCol; + if (Element2 == NULL) + { +/* Element2 does not exist, move Element1 down to Row2. */ + if ( ElementBelowRow1 != NULL AND ElementBelowRow1->Row < Row2 ) + { +/* Element1 must be removed from linked list and moved. */ *ElementAboveRow1 = ElementBelowRow1; - /* Search column for Row2. */ +/* Search column for Row2. */ pElement = ElementBelowRow1; - do { - ElementAboveRow2 = &(pElement->NextInCol); + do + { ElementAboveRow2 = &(pElement->NextInCol); pElement = *ElementAboveRow2; - } while (pElement != NULL && pElement->Row < Row2); + } while (pElement != NULL AND pElement->Row < Row2); - /* Place Element1 in Row2. */ +/* Place Element1 in Row2. */ *ElementAboveRow2 = Element1; Element1->NextInCol = pElement; *ElementAboveRow1 =ElementBelowRow1; } Element1->Row = Row2; - } else { - /* Element2 does exist, and the two elements must be exchanged. */ - if ( ElementBelowRow1->Row == Row2) { - /* Element2 is just below Element1, exchange them. */ + } + else + { +/* Element2 does exist, and the two elements must be exchanged. */ + if ( ElementBelowRow1->Row == Row2) + { +/* Element2 is just below Element1, exchange them. */ Element1->NextInCol = Element2->NextInCol; Element2->NextInCol = Element1; *ElementAboveRow1 = Element2; - } else { - /* Element2 is not just below Element1 and must be searched for. */ + } + else + { +/* Element2 is not just below Element1 and must be searched for. */ pElement = ElementBelowRow1; - do { - ElementAboveRow2 = &(pElement->NextInCol); + do + { ElementAboveRow2 = &(pElement->NextInCol); pElement = *ElementAboveRow2; } while (pElement->Row < Row2); ElementBelowRow2 = Element2->NextInCol; - /* Switch Element1 and Element2. */ +/* Switch Element1 and Element2. */ *ElementAboveRow1 = Element2; Element2->NextInCol = ElementBelowRow1; *ElementAboveRow2 = Element1; @@ -2383,20 +2500,22 @@ ExchangeColElements( MatrixPtr Matrix, int Row1, ElementPtr Element1, int Row2, Element1->Row = Row2; Element2->Row = Row1; } - } else { - /* Element1 does not exist. */ + } + else + { +/* Element1 does not exist. */ ElementBelowRow1 = pElement; - /* Find Element2. */ - if (ElementBelowRow1->Row != Row2) { - do { - ElementAboveRow2 = &(pElement->NextInCol); +/* Find Element2. */ + if (ElementBelowRow1->Row != Row2) + { do + { ElementAboveRow2 = &(pElement->NextInCol); pElement = *ElementAboveRow2; } while (pElement->Row < Row2); - ElementBelowRow2 = Element2->NextInCol; + ElementBelowRow2 = Element2->NextInCol; - /* Move Element2 to Row1. */ +/* Move Element2 to Row1. */ *ElementAboveRow2 = Element2->NextInCol; *ElementAboveRow1 = Element2; Element2->NextInCol = ElementBelowRow1; @@ -2417,7 +2536,7 @@ ExchangeColElements( MatrixPtr Matrix, int Row1, ElementPtr Element1, int Row2, * * Performs all required operations to exchange two elements in a row. * Those operations are: restring NextInRow pointers and swapping column - * strchres in the MatrixElements. + * indexes in the MatrixElements. * * >>> Arguments: * Matrix (MatrixPtr) @@ -2451,59 +2570,73 @@ ExchangeColElements( MatrixPtr Matrix, int Row1, ElementPtr Element1, int Row2, */ static void -ExchangeRowElements( MatrixPtr Matrix, int Col1, ElementPtr Element1, int Col2, ElementPtr Element2, int Row ) +ExchangeRowElements( + MatrixPtr Matrix, + int Col1, + register ElementPtr Element1, + int Col2, + register ElementPtr Element2, + int Row +) { - ElementPtr *ElementLeftOfCol1, *ElementLeftOfCol2; - ElementPtr ElementRightOfCol1, ElementRightOfCol2; - ElementPtr pElement; +ElementPtr *ElementLeftOfCol1, *ElementLeftOfCol2; +ElementPtr ElementRightOfCol1, ElementRightOfCol2; +register ElementPtr pElement; - /* Begin `ExchangeRowElements'. */ - /* Search to find the ElementLeftOfCol1. */ +/* Begin `ExchangeRowElements'. */ +/* Search to find the ElementLeftOfCol1. */ ElementLeftOfCol1 = &(Matrix->FirstInRow[Row]); pElement = *ElementLeftOfCol1; - while (pElement->Col < Col1) { - ElementLeftOfCol1 = &(pElement->NextInRow); + while (pElement->Col < Col1) + { ElementLeftOfCol1 = &(pElement->NextInRow); pElement = *ElementLeftOfCol1; } - if (Element1 != NULL) { - ElementRightOfCol1 = Element1->NextInRow; - if (Element2 == NULL) { - /* Element2 does not exist, move Element1 to right to Col2. */ - if ( ElementRightOfCol1 != NULL && ElementRightOfCol1->Col < Col2 ) { - /* Element1 must be removed from linked list and moved. */ + if (Element1 != NULL) + { ElementRightOfCol1 = Element1->NextInRow; + if (Element2 == NULL) + { +/* Element2 does not exist, move Element1 to right to Col2. */ + if ( ElementRightOfCol1 != NULL AND ElementRightOfCol1->Col < Col2 ) + { +/* Element1 must be removed from linked list and moved. */ *ElementLeftOfCol1 = ElementRightOfCol1; - /* Search Row for Col2. */ +/* Search Row for Col2. */ pElement = ElementRightOfCol1; - do { - ElementLeftOfCol2 = &(pElement->NextInRow); + do + { ElementLeftOfCol2 = &(pElement->NextInRow); pElement = *ElementLeftOfCol2; - } while (pElement != NULL && pElement->Col < Col2); + } while (pElement != NULL AND pElement->Col < Col2); - /* Place Element1 in Col2. */ +/* Place Element1 in Col2. */ *ElementLeftOfCol2 = Element1; Element1->NextInRow = pElement; *ElementLeftOfCol1 =ElementRightOfCol1; } Element1->Col = Col2; - } else { - /* Element2 does exist, and the two elements must be exchanged. */ - if ( ElementRightOfCol1->Col == Col2) { - /* Element2 is just right of Element1, exchange them. */ + } + else + { +/* Element2 does exist, and the two elements must be exchanged. */ + if ( ElementRightOfCol1->Col == Col2) + { +/* Element2 is just right of Element1, exchange them. */ Element1->NextInRow = Element2->NextInRow; Element2->NextInRow = Element1; *ElementLeftOfCol1 = Element2; - } else { - /* Element2 is not just right of Element1 and must be searched for. */ + } + else + { +/* Element2 is not just right of Element1 and must be searched for. */ pElement = ElementRightOfCol1; - do { - ElementLeftOfCol2 = &(pElement->NextInRow); + do + { ElementLeftOfCol2 = &(pElement->NextInRow); pElement = *ElementLeftOfCol2; } while (pElement->Col < Col2); ElementRightOfCol2 = Element2->NextInRow; - /* Switch Element1 and Element2. */ +/* Switch Element1 and Element2. */ *ElementLeftOfCol1 = Element2; Element2->NextInRow = ElementRightOfCol1; *ElementLeftOfCol2 = Element1; @@ -2512,20 +2645,22 @@ ExchangeRowElements( MatrixPtr Matrix, int Col1, ElementPtr Element1, int Col2, Element1->Col = Col2; Element2->Col = Col1; } - } else { - /* Element1 does not exist. */ + } + else + { +/* Element1 does not exist. */ ElementRightOfCol1 = pElement; - /* Find Element2. */ - if (ElementRightOfCol1->Col != Col2) { - do { - ElementLeftOfCol2 = &(pElement->NextInRow); +/* Find Element2. */ + if (ElementRightOfCol1->Col != Col2) + { do + { ElementLeftOfCol2 = &(pElement->NextInRow); pElement = *ElementLeftOfCol2; } while (pElement->Col < Col2); ElementRightOfCol2 = Element2->NextInRow; - /* Move Element2 to Col1. */ +/* Move Element2 to Col1. */ *ElementLeftOfCol2 = Element2->NextInRow; *ElementLeftOfCol1 = Element2; Element2->NextInRow = ElementRightOfCol1; @@ -2564,7 +2699,7 @@ ExchangeRowElements( MatrixPtr Matrix, int Col1, ElementPtr Element1, int Col2, * pSub (ElementPtr) * Points to elements in the reduced submatrix. * Row (int) - * Rowstrchr. + * Row index. * pUpper (ElementPtr) * Points to matrix element in upper triangular row. * @@ -2573,40 +2708,49 @@ ExchangeRowElements( MatrixPtr Matrix, int Col1, ElementPtr Element1, int Col2, */ static void -RealRowColElimination( MatrixPtr Matrix, ElementPtr pPivot ) +RealRowColElimination( + MatrixPtr Matrix, + register ElementPtr pPivot +) { - ElementPtr pSub; - int Row; - ElementPtr pLower, pUpper; +#if REAL +register ElementPtr pSub, *ppAbove; +register int Row; +register ElementPtr pLower, pUpper; - /* Begin `RealRowColElimination'. */ +/* Begin `RealRowColElimination'. */ - /* Test for zero pivot. */ - if (ABS(pPivot->Real) == 0.0) { - (void)MatrixIsSingular( Matrix, pPivot->Row ); +/* Test for zero pivot. */ + if (ABS(pPivot->Real) == 0.0) + { (void)MatrixIsSingular( Matrix, pPivot->Row ); return; } pPivot->Real = 1.0 / pPivot->Real; pUpper = pPivot->NextInRow; - while (pUpper != NULL) { - /* Calculate upper triangular element. */ + while (pUpper != NULL) + { +/* Calculate upper triangular element. */ pUpper->Real *= pPivot->Real; pSub = pUpper->NextInCol; pLower = pPivot->NextInCol; - while (pLower != NULL) { - Row = pLower->Row; + ppAbove = &pUpper->NextInCol; + while (pLower != NULL) + { Row = pLower->Row; - /* Find element in row that lines up with current lower triangular element. */ - while (pSub != NULL && pSub->Row < Row) +/* Find element in row that lines up with current lower triangular element. */ + while (pSub != NULL AND pSub->Row < Row) + { ppAbove = &pSub->NextInCol; pSub = pSub->NextInCol; + } - /* Test to see if desired element was not found, if not, create fill-in. */ - if (pSub == NULL || pSub->Row > Row) { - pSub = CreateFillin( Matrix, Row, pUpper->Col ); - if (pSub == NULL) { - Matrix->Error = spNO_MEMORY; +/* Test to see if desired element was not found, if not, create fill-in. */ + if (pSub == NULL OR pSub->Row > Row) + { pSub = spcCreateElement( Matrix, Row, pUpper->Col, + &pLower->NextInRow, ppAbove, YES ); + if (pSub == NULL) + { Matrix->Error = spNO_MEMORY; return; } } @@ -2617,6 +2761,7 @@ RealRowColElimination( MatrixPtr Matrix, ElementPtr pPivot ) pUpper = pUpper->NextInRow; } return; +#endif /* REAL */ } @@ -2646,7 +2791,7 @@ RealRowColElimination( MatrixPtr Matrix, ElementPtr pPivot ) * pSub (ElementPtr) * Points to elements in the reduced submatrix. * Row (int) - * Rowstrchr. + * Row index. * pUpper (ElementPtr) * Points to matrix element in upper triangular row. * @@ -2655,46 +2800,55 @@ RealRowColElimination( MatrixPtr Matrix, ElementPtr pPivot ) */ static void -ComplexRowColElimination( MatrixPtr Matrix, ElementPtr pPivot ) +ComplexRowColElimination( + MatrixPtr Matrix, + register ElementPtr pPivot +) { - ElementPtr pSub; - int Row; - ElementPtr pLower, pUpper; +#if spCOMPLEX +register ElementPtr pSub, *ppAbove; +register int Row; +register ElementPtr pLower, pUpper; - /* Begin `ComplexRowColElimination'. */ +/* Begin `ComplexRowColElimination'. */ - /* Test for zero pivot. */ - if (ELEMENT_MAG(pPivot) == 0.0) { - (void)MatrixIsSingular( Matrix, pPivot->Row ); +/* Test for zero pivot. */ + if (ELEMENT_MAG(pPivot) == 0.0) + { (void)MatrixIsSingular( Matrix, pPivot->Row ); return; } CMPLX_RECIPROCAL(*pPivot, *pPivot); pUpper = pPivot->NextInRow; - while (pUpper != NULL) { - /* Calculate upper triangular element. */ - /* Cmplx expr: *pUpper = *pUpper * (1.0 / *pPivot). */ + while (pUpper != NULL) + { +/* Calculate upper triangular element. */ +/* Cmplx expr: *pUpper = *pUpper * (1.0 / *pPivot). */ CMPLX_MULT_ASSIGN(*pUpper, *pPivot); pSub = pUpper->NextInCol; pLower = pPivot->NextInCol; - while (pLower != NULL) { - Row = pLower->Row; + ppAbove = &pUpper->NextInCol; + while (pLower != NULL) + { Row = pLower->Row; - /* Find element in row that lines up with current lower triangular element. */ - while (pSub != NULL && pSub->Row < Row) +/* Find element in row that lines up with current lower triangular element. */ + while (pSub != NULL AND pSub->Row < Row) + { ppAbove = &pSub->NextInCol; pSub = pSub->NextInCol; + } - /* Test to see if desired element was not found, if not, create fill-in. */ - if (pSub == NULL || pSub->Row > Row) { - pSub = CreateFillin( Matrix, Row, pUpper->Col ); - if (pSub == NULL) { - Matrix->Error = spNO_MEMORY; +/* Test to see if desired element was not found, if not, create fill-in. */ + if (pSub == NULL OR pSub->Row > Row) + { pSub = spcCreateElement( Matrix, Row, pUpper->Col, + &pLower->NextInRow, ppAbove, YES ); + if (pSub == NULL) + { Matrix->Error = spNO_MEMORY; return; } } - /* Cmplx expr: pElement -= *pUpper * pLower. */ +/* Cmplx expr: pElement -= *pUpper * pLower. */ CMPLX_MULT_SUBT_ASSIGN(*pSub, *pUpper, *pLower); pSub = pSub->NextInCol; pLower = pLower->NextInCol; @@ -2702,6 +2856,7 @@ ComplexRowColElimination( MatrixPtr Matrix, ElementPtr pPivot ) pUpper = pUpper->NextInRow; } return; +#endif /* spCOMPLEX */ } @@ -2722,9 +2877,9 @@ ComplexRowColElimination( MatrixPtr Matrix, ElementPtr pPivot ) * * >>> Local variables: * Row (int) - * Rowstrchr. + * Row index. * Col (int) - * Columnstrchr. + * Column index. * ColPtr (ElementPtr) * Points to matrix element in upper triangular column. * RowPtr (ElementPtr) @@ -2732,50 +2887,52 @@ ComplexRowColElimination( MatrixPtr Matrix, ElementPtr pPivot ) */ static void -UpdateMarkowitzNumbers( MatrixPtr Matrix, ElementPtr pPivot ) +UpdateMarkowitzNumbers( + MatrixPtr Matrix, + ElementPtr pPivot +) { - int Row, Col; - ElementPtr ColPtr, RowPtr; - int *MarkoRow = Matrix->MarkowitzRow; - int *MarkoCol = Matrix->MarkowitzCol; - double Product; +register int Row, Col; +register ElementPtr ColPtr, RowPtr; +register int *MarkoRow = Matrix->MarkowitzRow, *MarkoCol = Matrix->MarkowitzCol; +double Product; - /* Begin `UpdateMarkowitzNumbers'. */ +/* Begin `UpdateMarkowitzNumbers'. */ - /* Update Markowitz numbers. */ - for (ColPtr = pPivot->NextInCol; ColPtr != NULL; ColPtr = ColPtr->NextInCol) { - Row = ColPtr->Row; +/* Update Markowitz numbers. */ + for (ColPtr = pPivot->NextInCol; ColPtr != NULL; ColPtr = ColPtr->NextInCol) + { Row = ColPtr->Row; --MarkoRow[Row]; - /* Form Markowitz product while being cautious of overflows. */ - if ((MarkoRow[Row] > LARGEST_SHORT_INTEGER && MarkoCol[Row] != 0) || - (MarkoCol[Row] > LARGEST_SHORT_INTEGER && MarkoRow[Row] != 0)) { - Product = MarkoCol[Row] * MarkoRow[Row]; +/* Form Markowitz product while being cautious of overflows. */ + if ((MarkoRow[Row] > LARGEST_SHORT_INTEGER AND MarkoCol[Row] != 0) OR + (MarkoCol[Row] > LARGEST_SHORT_INTEGER AND MarkoRow[Row] != 0)) + { Product = (double)MarkoCol[Row] * (double)MarkoRow[Row]; if (Product >= LARGEST_LONG_INTEGER) Matrix->MarkowitzProd[Row] = LARGEST_LONG_INTEGER; else Matrix->MarkowitzProd[Row] = (long)Product; - } else Matrix->MarkowitzProd[Row] = MarkoRow[Row] * MarkoCol[Row]; + } + else Matrix->MarkowitzProd[Row] = MarkoRow[Row] * MarkoCol[Row]; if (MarkoRow[Row] == 0) Matrix->Singletons++; } - for (RowPtr = pPivot->NextInRow; - RowPtr != NULL; - RowPtr = RowPtr->NextInRow) { - Col = RowPtr->Col; + for (RowPtr = pPivot->NextInRow; RowPtr != NULL; RowPtr = RowPtr->NextInRow) + { Col = RowPtr->Col; --MarkoCol[Col]; - /* Form Markowitz product while being cautious of overflows. */ - if ((MarkoRow[Col] > LARGEST_SHORT_INTEGER && MarkoCol[Col] != 0) || - (MarkoCol[Col] > LARGEST_SHORT_INTEGER && MarkoRow[Col] != 0)) { - Product = MarkoCol[Col] * MarkoRow[Col]; +/* Form Markowitz product while being cautious of overflows. */ + if ((MarkoRow[Col] > LARGEST_SHORT_INTEGER AND MarkoCol[Col] != 0) OR + (MarkoCol[Col] > LARGEST_SHORT_INTEGER AND MarkoRow[Col] != 0)) + { Product = (double)MarkoCol[Col] * (double)MarkoRow[Col]; if (Product >= LARGEST_LONG_INTEGER) Matrix->MarkowitzProd[Col] = LARGEST_LONG_INTEGER; else Matrix->MarkowitzProd[Col] = (long)Product; - } else Matrix->MarkowitzProd[Col] = MarkoRow[Col] * MarkoCol[Col]; - if ((MarkoCol[Col] == 0) && (MarkoRow[Col] != 0)) + } + else Matrix->MarkowitzProd[Col] = MarkoRow[Col] * MarkoCol[Col]; + if ((MarkoCol[Col] == 0) AND (MarkoRow[Col] != 0)) Matrix->Singletons++; } return; @@ -2785,77 +2942,6 @@ UpdateMarkowitzNumbers( MatrixPtr Matrix, ElementPtr pPivot ) - - - -/* - * CREATE FILL-IN - * - * This routine is used to create fill-ins and splice them into the - * matrix. - * - * >>> Returns: - * Pointer to fill-in. - * - * >>> Arguments: - * Matrix (MatrixPtr) - * Pointer to the matrix. - * Col (int) - * Columnstrchr for element. - * Row (int) - * Rowstrchr for element. - * - * >>> Local variables: - * pElement (ElementPtr) - * Pointer to an element in the matrix. - * ppElementAbove (ElementPtr *) - * This contains the address of the pointer to the element just above the - * one being created. It is used to speed the search and it is updated - * with address of the created element. - * - * >>> Possible errors: - * spNO_MEMORY - */ - -static ElementPtr -CreateFillin( MatrixPtr Matrix, int Row, int Col ) -{ - ElementPtr pElement, *ppElementAbove; - - /* Begin `CreateFillin'. */ - - /* Find Element above fill-in. */ - ppElementAbove = &Matrix->FirstInCol[Col]; - pElement = *ppElementAbove; - while (pElement != NULL) { - if (pElement->Row < Row) { - ppElementAbove = &pElement->NextInCol; - pElement = *ppElementAbove; - } else break; /* while loop */ - } - - /* End of search, create the element. */ - pElement = spcCreateElement( Matrix, Row, Col, ppElementAbove, YES ); - - /* Update Markowitz counts and products. */ - Matrix->MarkowitzProd[Row] = ++Matrix->MarkowitzRow[Row] * - Matrix->MarkowitzCol[Row]; - if ((Matrix->MarkowitzRow[Row] == 1) && (Matrix->MarkowitzCol[Row] != 0)) - Matrix->Singletons--; - Matrix->MarkowitzProd[Col] = ++Matrix->MarkowitzCol[Col] * - Matrix->MarkowitzRow[Col]; - if ((Matrix->MarkowitzRow[Col] != 0) && (Matrix->MarkowitzCol[Col] == 1)) - Matrix->Singletons--; - - return pElement; -} - - - - - - - /* * ZERO PIVOT ENCOUNTERED @@ -2874,9 +2960,12 @@ CreateFillin( MatrixPtr Matrix, int Row, int Col ) */ static int -MatrixIsSingular( MatrixPtr Matrix, int Step ) +MatrixIsSingular( + MatrixPtr Matrix, + int Step +) { - /* Begin `MatrixIsSingular'. */ +/* Begin `MatrixIsSingular'. */ Matrix->SingularRow = Matrix->IntToExtRowMap[ Step ]; Matrix->SingularCol = Matrix->IntToExtColMap[ Step ]; @@ -2885,9 +2974,12 @@ MatrixIsSingular( MatrixPtr Matrix, int Step ) static int -ZeroPivot( MatrixPtr Matrix, int Step ) +ZeroPivot( + MatrixPtr Matrix, + int Step +) { - /* Begin `ZeroPivot'. */ +/* Begin `ZeroPivot'. */ Matrix->SingularRow = Matrix->IntToExtRowMap[ Step ]; Matrix->SingularCol = Matrix->IntToExtColMap[ Step ]; @@ -2909,28 +3001,23 @@ ZeroPivot( MatrixPtr Matrix, int Step ) */ static void -WriteStatus( MatrixPtr Matrix, int Step ) +WriteStatus( + MatrixPtr Matrix, + int Step +) { - int I; +int I; - /* Begin `WriteStatus'. */ +/* Begin `WriteStatus'. */ printf("Step = %1d ", Step); printf("Pivot found at %1d,%1d using ", Matrix->PivotsOriginalRow, - Matrix->PivotsOriginalCol); - switch(Matrix->PivotSelectionMethod) { - case 's': - printf("SearchForSingleton\n"); - break; - case 'q': - printf("QuicklySearchDiagonal\n"); - break; - case 'd': - printf("SearchDiagonal\n"); - break; - case 'e': - printf("SearchEntireMatrix\n"); - break; + Matrix->PivotsOriginalCol); + switch(Matrix->PivotSelectionMethod) + { case 's': printf("SearchForSingleton\n"); break; + case 'q': printf("QuicklySearchDiagonal\n"); break; + case 'd': printf("SearchDiagonal\n"); break; + case 'e': printf("SearchEntireMatrix\n"); break; } printf("MarkowitzRow = "); @@ -2970,6 +3057,8 @@ WriteStatus( MatrixPtr Matrix, int Step ) printf("%2d ", Matrix->ExtToIntColMap[I]); printf("\n\n"); +/* spPrint((char *)Matrix, NO, YES); */ + return; } diff --git a/src/maths/sparse/spoutput.c b/src/maths/sparse/spOutput.c similarity index 59% rename from src/maths/sparse/spoutput.c rename to src/maths/sparse/spOutput.c index 9b37ca26d..ca3a80490 100644 --- a/src/maths/sparse/spoutput.c +++ b/src/maths/sparse/spOutput.c @@ -4,11 +4,19 @@ * Author: Advisor: * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli * UC Berkeley - * + */ +/*! \file + * * This file contains the output-to-file and output-to-screen routines for * the matrix package. * - * >>> User accessible functions contained in this file: + * Objects that begin with the \a spc prefix are considered private + * and should not be used. + * + * \author + * Kenneth S. Kundert + */ +/* >>> User accessible functions contained in this file: * spPrint * spFileMatrix * spFileVector @@ -21,19 +29,13 @@ /* * 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. + * Copyright (c) 1985-2003 + * by Kenneth S. Kundert */ + + + /* * IMPORTS * @@ -45,53 +47,44 @@ * spDefs.h * Matrix type and macro definitions for the sparse matrix routines. */ -#include -#include #define spINSIDE_SPARSE -#include "spconfig.h" +#include +#include "spConfig.h" #include "ngspice/spmatrix.h" -#include "spdefs.h" +#include "spDefs.h" -int Printer_Width = PRINTER_WIDTH; -#include "ngspice/config.h" -#ifdef HAS_WINGUI -#include "ngspice/wstdio.h" -#endif #if DOCUMENTATION -/* - * PRINT MATRIX - * +/*! * Formats and send the matrix to standard output. Some elementary * statistics are also output. The matrix is output in a format that is * readable by people. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to matrix. - * PrintReordered (int) + * \param PrintReordered * Indicates whether the matrix should be printed out in its original * form, as input by the user, or whether it should be printed in its * reordered form, as used by the matrix routines. A zero indicates that * the matrix should be printed as inputed, a one indicates that it * should be printed reordered. - * Data (int) - * Boolean flag that when FALSE indicates that output should be + * \param Data + * Boolean flag that when false indicates that output should be * compressed such that only the existence of an element should be * indicated rather than giving the actual value. Thus 11 times as * many can be printed on a row. A zero signifies that the matrix * should be printed compressed. A one indicates that the matrix * should be printed in all its glory. - * Header (int) + * \param Header * Flag indicating that extra information should be given, such as row * and column numbers. - * - * >>> Local variables: + */ +/* >>> Local variables: * Col (int) * Column being printed. * ElementCount (int) @@ -135,75 +128,57 @@ int Printer_Width = PRINTER_WIDTH; */ void -spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header) +spPrint( + spMatrix eMatrix, + int PrintReordered, + int Data, + int Header +) { - int J = 0; - int I, Row, Col, Size, Top; - int StartCol = 1, StopCol, Columns, ElementCount = 0; - double Magnitude; - double SmallestDiag = 0; - double SmallestElement = 0; - double LargestElement = 0.0, LargestDiag = 0.0; - ElementPtr pElement, *pImagElements; - int *PrintOrdToIntRowMap, *PrintOrdToIntColMap; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int J = 0; +int I, Row, Col, Size, Top, StartCol = 1, StopCol, Columns, ElementCount = 0; +double Magnitude, SmallestDiag, SmallestElement; +double LargestElement = 0.0, LargestDiag = 0.0; +ElementPtr pElement, pImagElements[PRINTER_WIDTH/10+1]; +int *PrintOrdToIntRowMap, *PrintOrdToIntColMap; - /* Begin `spPrint'. */ - assert( IS_SPARSE( Matrix ) ); +/* Begin `spPrint'. */ + ASSERT_IS_SPARSE( Matrix ); Size = Matrix->Size; - SP_CALLOC(pImagElements, ElementPtr, Printer_Width / 10 + 1); - if ( pImagElements == NULL) - { - Matrix->Error = spNO_MEMORY; - SP_FREE(pImagElements); - return; - } - /* Create a packed external to internal row and column translation - array. */ +/* Create a packed external to internal row and column translation array. */ # if TRANSLATE Top = Matrix->AllocatedExtSize; #else Top = Matrix->AllocatedSize; #endif - SP_CALLOC( PrintOrdToIntRowMap, int, Top + 1 ); - if ( PrintOrdToIntRowMap == NULL) - { - Matrix->Error = spNO_MEMORY; - SP_FREE(pImagElements); - return; - } - SP_CALLOC( PrintOrdToIntColMap, int, Top + 1 ); - if (PrintOrdToIntColMap == NULL) - { - Matrix->Error = spNO_MEMORY; - SP_FREE(pImagElements); - SP_FREE(PrintOrdToIntRowMap); + CALLOC( PrintOrdToIntRowMap, int, Top + 1 ); + CALLOC( PrintOrdToIntColMap, int, Top + 1 ); + if ( PrintOrdToIntRowMap == NULL OR PrintOrdToIntColMap == NULL) + { Matrix->Error = spNO_MEMORY; return; } for (I = 1; I <= Size; I++) - { - PrintOrdToIntRowMap[ Matrix->IntToExtRowMap[I] ] = I; + { PrintOrdToIntRowMap[ Matrix->IntToExtRowMap[I] ] = I; PrintOrdToIntColMap[ Matrix->IntToExtColMap[I] ] = I; } - /* Pack the arrays. */ +/* Pack the arrays. */ for (J = 1, I = 1; I <= Top; I++) - { - if (PrintOrdToIntRowMap[I] != 0) + { if (PrintOrdToIntRowMap[I] != 0) PrintOrdToIntRowMap[ J++ ] = PrintOrdToIntRowMap[ I ]; } for (J = 1, I = 1; I <= Top; I++) - { - if (PrintOrdToIntColMap[I] != 0) + { if (PrintOrdToIntColMap[I] != 0) PrintOrdToIntColMap[ J++ ] = PrintOrdToIntColMap[ I ]; } - /* Print header. */ +/* Print header. */ if (Header) - { - printf("MATRIX SUMMARY\n\n"); + { printf("MATRIX SUMMARY\n\n"); printf("Size of matrix = %1d x %1d.\n", Size, Size); - if ( Matrix->Reordered && PrintReordered ) + if ( Matrix->Reordered AND PrintReordered ) printf("Matrix has been reordered.\n"); putchar('\n'); @@ -215,31 +190,31 @@ spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header) SmallestElement = LARGEST_REAL; SmallestDiag = SmallestElement; } + if (Size == 0) return; - /* Determine how many columns to use. */ - Columns = Printer_Width; +/* Determine how many columns to use. */ + Columns = PRINTER_WIDTH; if (Header) Columns -= 5; if (Data) Columns = (Columns+1) / 10; - /* Print matrix by printing groups of complete columns until all - * the columns are printed. */ +/* + * Print matrix by printing groups of complete columns until all the columns + * are printed. + */ J = 0; while ( J <= Size ) - { - /* Calculatestrchr of last column to printed in this group. */ - StopCol = StartCol + Columns - 1; + +/* Calculate index of last column to printed in this group. */ + { StopCol = StartCol + Columns - 1; if (StopCol > Size) StopCol = Size; - /* Label the columns. */ +/* Label the columns. */ if (Header) - { - if (Data) - { - printf(" "); + { if (Data) + { printf(" "); for (I = StartCol; I <= StopCol; I++) - { - if (PrintReordered) + { if (PrintReordered) Col = I; else Col = PrintOrdToIntColMap[I]; @@ -248,70 +223,64 @@ spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header) printf("\n\n"); } else - { - if (PrintReordered) + { if (PrintReordered) printf("Columns %1d to %1d.\n",StartCol,StopCol); else - { - printf("Columns %1d to %1d.\n", - Matrix->IntToExtColMap[ PrintOrdToIntColMap[StartCol] ], - Matrix->IntToExtColMap[ PrintOrdToIntColMap[StopCol] ]); + { printf("Columns %1d to %1d.\n", + Matrix->IntToExtColMap[ PrintOrdToIntColMap[StartCol] ], + Matrix->IntToExtColMap[ PrintOrdToIntColMap[StopCol] ]); } } } - /* Print every row ... */ +/* Print every row ... */ for (I = 1; I <= Size; I++) - { - if (PrintReordered) + { if (PrintReordered) Row = I; else Row = PrintOrdToIntRowMap[I]; if (Header) - { - if (PrintReordered && !Data) + { if (PrintReordered AND NOT Data) printf("%4d", I); else printf("%4d", Matrix->IntToExtRowMap[ Row ]); - if (!Data) putchar(' '); + if (NOT Data) putchar(' '); } - /* ... in each column of the group. */ +/* ... in each column of the group. */ for (J = StartCol; J <= StopCol; J++) - { - if (PrintReordered) + { if (PrintReordered) Col = J; else Col = PrintOrdToIntColMap[J]; pElement = Matrix->FirstInCol[Col]; - while(pElement != NULL && pElement->Row != Row) + while(pElement != NULL AND pElement->Row != Row) pElement = pElement->NextInCol; if (Data) pImagElements[J - StartCol] = pElement; if (pElement != NULL) - { - /* Case where element exists */ - if (Data) - printf(" %9.3g", pElement->Real); + +/* Case where element exists */ + { if (Data) + printf(" %9.3g", (double)pElement->Real); else putchar('x'); - /* Update status variables */ +/* Update status variables */ if ( (Magnitude = ELEMENT_MAG(pElement)) > LargestElement ) LargestElement = Magnitude; - if ((Magnitude < SmallestElement) && (Magnitude != 0.0)) + if ((Magnitude < SmallestElement) AND (Magnitude != 0.0)) SmallestElement = Magnitude; ElementCount++; } - /* Case where element is structurally zero */ +/* Case where element is structurally zero */ else - { - if (Data) + { if (Data) printf(" ..."); else putchar('.'); @@ -319,68 +288,61 @@ spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header) } putchar('\n'); - if (Matrix->Complex && Data) - { - printf(" "); +#if spCOMPLEX + if (Matrix->Complex AND Data) + { if (Header) + printf(" "); for (J = StartCol; J <= StopCol; J++) - { - if (pImagElements[J - StartCol] != NULL) - { - printf(" %8.2gj", - pImagElements[J-StartCol]->Imag); + { if (pImagElements[J - StartCol] != NULL) + { printf(" %8.2gj", + (double)pImagElements[J-StartCol]->Imag); } else printf(" "); } putchar('\n'); } +#endif /* spCOMPLEX */ } - /* Calculatestrchr of first column in next group. */ +/* Calculate index of first column in next group. */ StartCol = StopCol; StartCol++; putchar('\n'); } if (Header) - { - printf("\nLargest element in matrix = %-1.4g.\n", LargestElement); + { printf("\nLargest element in matrix = %-1.4g.\n", LargestElement); printf("Smallest element in matrix = %-1.4g.\n", SmallestElement); - /* Search for largest and smallest diagonal values */ +/* Search for largest and smallest diagonal values */ for (I = 1; I <= Size; I++) - { - if (Matrix->Diag[I] != NULL) - { - Magnitude = ELEMENT_MAG( Matrix->Diag[I] ); + { if (Matrix->Diag[I] != NULL) + { Magnitude = ELEMENT_MAG( Matrix->Diag[I] ); if ( Magnitude > LargestDiag ) LargestDiag = Magnitude; if ( Magnitude < SmallestDiag ) SmallestDiag = Magnitude; } } - /* Print the largest and smallest diagonal values */ + /* Print the largest and smallest diagonal values */ if ( Matrix->Factored ) - { - printf("\nLargest diagonal element = %-1.4g.\n", LargestDiag); + { printf("\nLargest diagonal element = %-1.4g.\n", LargestDiag); printf("Smallest diagonal element = %-1.4g.\n", SmallestDiag); } else - { - printf("\nLargest pivot element = %-1.4g.\n", LargestDiag); + { printf("\nLargest pivot element = %-1.4g.\n", LargestDiag); printf("Smallest pivot element = %-1.4g.\n", SmallestDiag); } - /* Calculate and print sparsity and number of fill-ins created. */ - printf("\nDensity = %2.2f%%.\n", ((double)(ElementCount * 100)) / - ((double)(Size * Size))); - - printf("Number of originals = %1d.\n", Matrix->Originals); - if (!Matrix->NeedsOrdering) + /* Calculate and print sparsity and number of fill-ins created. */ + printf("\nDensity = %2.2f%%.\n", ((double)ElementCount * 100.0) + / (((double)Size * (double)Size))); + if (NOT Matrix->NeedsOrdering) printf("Number of fill-ins = %1d.\n", Matrix->Fillins); } putchar('\n'); (void)fflush(stdout); - SP_FREE(PrintOrdToIntColMap); - SP_FREE(PrintOrdToIntRowMap); + FREE(PrintOrdToIntColMap); + FREE(PrintOrdToIntRowMap); return; } @@ -394,36 +356,33 @@ spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header) -/* - * OUTPUT MATRIX TO FILE - * +/*! * Writes matrix to file in format suitable to be read back in by the * matrix test program. * - * >>> Returns: + * \return * One is returned if routine was successful, otherwise zero is returned. - * The calling function can query errno (the system global error variable) + * The calling function can query \a errno (the system global error variable) * as to the reason why this routine failed. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to matrix. - * File (char *) + * \param File * Name of file into which matrix is to be written. - * Label (char *) + * \param Label * String that is transferred to file and is used as a label. - * Reordered (int) + * \param Reordered * Specifies whether matrix should be output in reordered form, * or in original order. - * Data (int) + * \param Data * Indicates that the element values should be output along with - * the indices for each element. This parameter must be TRUE if + * the indices for each element. This parameter must be true if * matrix is to be read by the sparse test program. - * Header (int) - * Indicates that header is desired. This parameter must be TRUE if + * \param Header + * Indicates that header is desired. This parameter must be true if * matrix is to be read by the sparse test program. - * - * >>> Local variables: + */ +/* >>> Local variables: * Col (int) * The original column number of the element being output. * pElement (ElementPtr) @@ -437,123 +396,118 @@ spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header) */ int -spFileMatrix(MatrixPtr Matrix, char *File, char *Label, int Reordered, - int Data, int Header) +spFileMatrix( + spMatrix eMatrix, + char *File, + char *Label, + int Reordered, + int Data, + int Header +) { - int I, Size; - ElementPtr pElement; - int Row, Col, Err; - FILE *pMatrixFile; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I, Size; +register ElementPtr pElement; +int Row, Col, Err; +FILE *pMatrixFile; - /* Begin `spFileMatrix'. */ - assert( IS_SPARSE( Matrix ) ); +/* Begin `spFileMatrix'. */ + ASSERT_IS_SPARSE( Matrix ); - /* Open file matrix file in write mode. */ +/* Open file matrix file in write mode. */ if ((pMatrixFile = fopen(File, "w")) == NULL) return 0; - /* Output header. */ +/* Output header. */ Size = Matrix->Size; if (Header) - { - if (Matrix->Factored && Data) - { - Err = fprintf(pMatrixFile, - "Warning : The following matrix is " - "factored in to LU form.\n"); - if (Err < 0) - return 0; + { if (Matrix->Factored AND Data) + { Err = fprintf + ( pMatrixFile, + "Warning : The following matrix is factored in to LU form.\n" + ); + if (Err < 0) return 0; } - if (fprintf(pMatrixFile, "%s\n", Label) < 0) - return 0; + if (fprintf(pMatrixFile, "%s\n", Label) < 0) return 0; Err = fprintf( pMatrixFile, "%d\t%s\n", Size, - (Matrix->Complex ? "complex" : "real")); - if (Err < 0) - return 0; + (Matrix->Complex ? "complex" : "real")); + if (Err < 0) return 0; } + if (Size == 0) return 1; - /* Output matrix. */ - if (!Data) - { - for (I = 1; I <= Size; I++) - { - pElement = Matrix->FirstInCol[I]; +/* Output matrix. */ + if (NOT Data) + { for (I = 1; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; while (pElement != NULL) - { - if (Reordered) - { - Row = pElement->Row; + { if (Reordered) + { Row = pElement->Row; Col = I; } else - { - Row = Matrix->IntToExtRowMap[pElement->Row]; + { Row = Matrix->IntToExtRowMap[pElement->Row]; Col = Matrix->IntToExtColMap[I]; } pElement = pElement->NextInCol; if (fprintf(pMatrixFile, "%d\t%d\n", Row, Col) < 0) return 0; } } - /* Output terminator, a line of zeros. */ +/* Output terminator, a line of zeros. */ if (Header) if (fprintf(pMatrixFile, "0\t0\n") < 0) return 0; } - if (Data && Matrix->Complex) - { - for (I = 1; I <= Size; I++) - { - pElement = Matrix->FirstInCol[I]; +#if spCOMPLEX + if (Data AND Matrix->Complex) + { for (I = 1; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; while (pElement != NULL) - { - if (Reordered) - { - Row = pElement->Row; + { if (Reordered) + { Row = pElement->Row; Col = I; } else - { - Row = Matrix->IntToExtRowMap[pElement->Row]; + { Row = Matrix->IntToExtRowMap[pElement->Row]; Col = Matrix->IntToExtColMap[I]; } Err = fprintf - ( pMatrixFile,"%d\t%d\t%-.15g\t%-.15g\n", - Row, Col, pElement->Real, pElement->Imag - ); + ( pMatrixFile,"%d\t%d\t%-.15g\t%-.15g\n", + Row, Col, (double)pElement->Real, (double)pElement->Imag + ); if (Err < 0) return 0; pElement = pElement->NextInCol; } } - /* Output terminator, a line of zeros. */ +/* Output terminator, a line of zeros. */ if (Header) if (fprintf(pMatrixFile,"0\t0\t0.0\t0.0\n") < 0) return 0; } +#endif /* spCOMPLEX */ - if (Data && !Matrix->Complex) - { - for (I = 1; I <= Size; I++) - { - pElement = Matrix->FirstInCol[I]; +#if REAL + if (Data AND NOT Matrix->Complex) + { for (I = 1; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; while (pElement != NULL) - { - Row = Matrix->IntToExtRowMap[pElement->Row]; + { Row = Matrix->IntToExtRowMap[pElement->Row]; Col = Matrix->IntToExtColMap[I]; Err = fprintf - ( pMatrixFile,"%d\t%d\t%-.15g\n", - Row, Col, pElement->Real - ); + ( pMatrixFile,"%d\t%d\t%-.15g\n", + Row, Col, (double)pElement->Real + ); if (Err < 0) return 0; pElement = pElement->NextInCol; } } - /* Output terminator, a line of zeros. */ +/* Output terminator, a line of zeros. */ if (Header) if (fprintf(pMatrixFile,"0\t0\t0.0\n") < 0) return 0; } +#endif /* REAL */ - /* Close file. */ +/* Close file. */ if (fclose(pMatrixFile) < 0) return 0; return 1; } @@ -564,79 +518,117 @@ spFileMatrix(MatrixPtr Matrix, char *File, char *Label, int Reordered, -/* - * OUTPUT SOURCE VECTOR TO FILE - * +/*! * Writes vector to file in format suitable to be read back in by the * matrix test program. This routine should be executed after the function * spFileMatrix. * - * >>> Returns: + * \return * One is returned if routine was successful, otherwise zero is returned. - * The calling function can query errno (the system global error variable) + * The calling function can query \a errno (the system global error variable) * as to the reason why this routine failed. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to matrix. - * File (char *) + * \param File * Name of file into which matrix is to be written. - * RHS (RealNumber []) - * Right-hand side vector, real portion - * iRHS (RealNumber []) - * Right-hand side vector, imaginary portion. - * - * >>> Local variables: + * \param RHS + * Right-hand side vector. This is only the real portion if + * \a spSEPARATED_COMPLEX_VECTORS is true. + * \param iRHS + * Right-hand side vector, imaginary portion. Not necessary if matrix + * is real or if \a spSEPARATED_COMPLEX_VECTORS is set false. + * \a iRHS is a macro that replaces itself with `, iRHS' if the options + * \a spCOMPLEX and \a spSEPARATED_COMPLEX_VECTORS are set, otherwise + * it disappears without a trace. + */ +/* >>> Local variables: * pMatrixFile (FILE *) * File pointer to the matrix file. * Size (int) * The size of the matrix. - * */ int -spFileVector(MatrixPtr Matrix, char *File, RealVector RHS, RealVector iRHS) +spFileVector( + spMatrix eMatrix, + char *File, + spREAL RHS[] +#if spCOMPLEX AND spSEPARATED_COMPLEX_VECTORS + , spREAL iRHS[] +#endif +) { - int I, Size, Err; - FILE *pMatrixFile; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I, Size, Err; +FILE *pMatrixFile; - /* Begin `spFileVector'. */ - assert( IS_SPARSE( Matrix ) && RHS != NULL); +/* Begin `spFileVector'. */ + ASSERT_IS_SPARSE( Matrix ); + vASSERT( RHS != NULL, "Vector missing" ); - if (File) { - /* Open File in write mode. */ - pMatrixFile = fopen(File,"w"); - if (pMatrixFile == NULL) - return 0; - } - else - pMatrixFile=stdout; +/* Open File in append mode. */ + if ((pMatrixFile = fopen(File,"a")) == NULL) + return 0; - /* Output vector. */ - Size = Matrix->Size; +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spCOMPLEX if (Matrix->Complex) { - for (I = 1; I <= Size; I++) - { - Err = fprintf - ( pMatrixFile, "%-.15g\t%-.15g\n", - RHS[I], iRHS[I] - ); - if (Err < 0) return 0; - } +#if spSEPARATED_COMPLEX_VECTORS + vASSERT( iRHS != NULL, "Imaginary vector missing" ); + --RHS; + --iRHS; +#else + RHS -= 2; +#endif } else +#endif /* spCOMPLEX */ + --RHS; +#endif /* NOT ARRAY_OFFSET */ + + +/* Output vector. */ + Size = Matrix->Size; + if (Size == 0) return 1; + +#if spCOMPLEX + if (Matrix->Complex) { - for (I = 1; I <= Size; I++) - { - if (fprintf(pMatrixFile, "%-.15g\n", RHS[I]) < 0) +#if spSEPARATED_COMPLEX_VECTORS + for (I = 1; I <= Size; I++) + { Err = fprintf + ( pMatrixFile, "%-.15g\t%-.15g\n", + (double)RHS[I], (double)iRHS[I] + ); + if (Err < 0) return 0; + } +#else + for (I = 1; I <= Size; I++) + { Err = fprintf + ( pMatrixFile, "%-.15g\t%-.15g\n", + (double)RHS[2*I], (double)RHS[2*I+1] + ); + if (Err < 0) return 0; + } +#endif + } +#endif /* spCOMPLEX */ +#if REAL AND spCOMPLEX + else +#endif +#if REAL + { for (I = 1; I <= Size; I++) + { if (fprintf(pMatrixFile, "%-.15g\n", (double)RHS[I]) < 0) return 0; } } +#endif /* REAL */ - /* Close file. */ - if (File) - if (fclose(pMatrixFile) < 0) return 0; +/* Close file. */ + if (fclose(pMatrixFile) < 0) return 0; return 1; } @@ -648,26 +640,23 @@ spFileVector(MatrixPtr Matrix, char *File, RealVector RHS, RealVector iRHS) -/* - * OUTPUT STATISTICS TO FILE - * +/*! * Writes useful information concerning the matrix to a file. Should be * executed after the matrix is factored. * - * >>> Returns: + * \return * One is returned if routine was successful, otherwise zero is returned. - * The calling function can query errno (the system global error variable) + * The calling function can query \a errno (the system global error variable) * as to the reason why this routine failed. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to matrix. - * File (char *) + * \param File * Name of file into which matrix is to be written. - * Label (char *) + * \param Label * String that is transferred to file and is used as a label. - * - * >>> Local variables: + */ +/* >>> Local variables: * Data (RealNumber) * The value of the matrix element being output. * LargestElement (RealNumber) @@ -685,24 +674,29 @@ spFileVector(MatrixPtr Matrix, char *File, RealVector RHS, RealVector iRHS) */ int -spFileStats(MatrixPtr Matrix, char *File, char *Label) +spFileStats( + spMatrix eMatrix, + char *File, + char *Label +) { - int Size, I; - ElementPtr pElement; - int NumberOfElements; - RealNumber Data, LargestElement, SmallestElement; - FILE *pStatsFile; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int Size, I; +register ElementPtr pElement; +int NumberOfElements; +RealNumber Data, LargestElement, SmallestElement; +FILE *pStatsFile; - /* Begin `spFileStats'. */ - assert( IS_SPARSE( Matrix ) ); +/* Begin `spFileStats'. */ + ASSERT_IS_SPARSE( Matrix ); - /* Open File in append mode. */ +/* Open File in append mode. */ if ((pStatsFile = fopen(File, "a")) == NULL) return 0; - /* Output statistics. */ +/* Output statistics. */ Size = Matrix->Size; - if (!Matrix->Factored) + if (NOT Matrix->Factored) fprintf(pStatsFile, "Matrix has not been factored.\n"); fprintf(pStatsFile, "||| Starting new matrix |||\n"); fprintf(pStatsFile, "%s\n", Label); @@ -711,22 +705,21 @@ spFileStats(MatrixPtr Matrix, char *File, char *Label) else fprintf(pStatsFile, "Matrix is real.\n"); fprintf(pStatsFile," Size = %d\n",Size); + if (Size == 0) return 1; - /* Search matrix. */ +/* Search matrix. */ NumberOfElements = 0; LargestElement = 0.0; SmallestElement = LARGEST_REAL; for (I = 1; I <= Size; I++) - { - pElement = Matrix->FirstInCol[I]; + { pElement = Matrix->FirstInCol[I]; while (pElement != NULL) - { - NumberOfElements++; + { NumberOfElements++; Data = ELEMENT_MAG(pElement); if (Data > LargestElement) LargestElement = Data; - if (Data < SmallestElement && Data != 0.0) + if (Data < SmallestElement AND Data != 0.0) SmallestElement = Data; pElement = pElement->NextInCol; } @@ -734,7 +727,7 @@ spFileStats(MatrixPtr Matrix, char *File, char *Label) SmallestElement = MIN( SmallestElement, LargestElement ); - /* Output remaining statistics. */ +/* Output remaining statistics. */ fprintf(pStatsFile, " Initial number of elements = %d\n", NumberOfElements - Matrix->Fillins); fprintf(pStatsFile, @@ -748,13 +741,13 @@ spFileStats(MatrixPtr Matrix, char *File, char *Label) fprintf(pStatsFile, " Average number of elements per row = %f\n", (double)NumberOfElements / (double)Size); fprintf(pStatsFile," Density = %f%%\n", - (double)(100.0*NumberOfElements)/(double)(Size*Size)); + (100.0*(double)NumberOfElements)/((double)Size*(double)Size)); fprintf(pStatsFile," Relative Threshold = %e\n", Matrix->RelThreshold); fprintf(pStatsFile," Absolute Threshold = %e\n", Matrix->AbsThreshold); fprintf(pStatsFile," Largest Element = %e\n", LargestElement); fprintf(pStatsFile," Smallest Element = %e\n\n\n", SmallestElement); - /* Close file. */ +/* Close file. */ (void)fclose(pStatsFile); return 1; } diff --git a/src/maths/sparse/spsmp.c b/src/maths/sparse/spSMP.c similarity index 53% rename from src/maths/sparse/spsmp.c rename to src/maths/sparse/spSMP.c index 471816e06..f40af9804 100644 --- a/src/maths/sparse/spsmp.c +++ b/src/maths/sparse/spSMP.c @@ -5,11 +5,14 @@ * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli * UC Berkeley * - * This module contains routines that make Sparse1.3 a direct - * replacement for the SMP sparse matrix package in Spice3c1 or Spice3d1. - * Sparse1.3 is in general a faster and more robust package than SMP. + * This module contains routines that make Sparse1.4 a direct + * replacement for the SMP sparse matrix package in Spice3c1 and Spice3d1. + * Sparse1.4 is in general a faster and more robust package than SMP. * These advantages become significant on large circuits. * + * This module is provided for convience only. It has not been tested + * with the recent version of Spice3 and is not supported. + * * >>> User accessible functions contained in this file: * SMPaddElt * SMPmakeElt @@ -29,8 +32,6 @@ * SMPprint * SMPgetError * SMPcProdDiag - * LoadGmin - * SMPfindElt */ /* @@ -45,10 +46,12 @@ * To be compatible with SPICE, the following Sparse compiler options * (in spConfig.h) should be set as shown below: * + * REAL YES * EXPANDABLE YES * TRANSLATE NO * INITIALIZE NO or YES, YES for use with test prog. * DIAGONAL_PIVOTING YES + * ARRAY_OFFSET YES * MODIFIED_MARKOWITZ NO * DELETE NO * STRIP NO @@ -62,7 +65,10 @@ * STABILITY NO * CONDITION NO * PSEUDOCONDITION NO + * FORTRAN NO * DEBUG YES + * spCOMPLEX 1 + * spSEPARATED_COMPLEX_VECTORS 1 * * spREAL double */ @@ -70,18 +76,10 @@ /* * 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 above copyright notice 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. + * Copyright (c) 1985-2003 by Kenneth S. Kundert */ + /* * IMPORTS * @@ -92,73 +90,71 @@ * Spice3's matrix macro definitions. */ -#include "ngspice/config.h" -#include -#include -#include #include "ngspice/spmatrix.h" -#include "spdefs.h" #include "ngspice/smpdefs.h" -#if defined (_MSC_VER) -extern double scalbn(double, int); -#define logb _logb -extern double logb(double); -#endif +#define NO 0 +#define YES 1 -static void LoadGmin(SMPmatrix *Matrix, double Gmin); +typedef spREAL RealNumber, *RealVector; +static void LoadGmin(char *Matrix, double Gmin); /* * SMPaddElt() */ int -SMPaddElt(SMPmatrix *Matrix, int Row, int Col, double Value) +SMPaddElt( Matrix, Row, Col, Value ) +SMPmatrix *Matrix; +int Row, Col; +double Value; { - *spGetElement( Matrix, Row, Col ) = Value; - return spError( Matrix ); + *spGetElement( (char *)Matrix, Row, Col ) = Value; + return spErrorState( (char *)Matrix ); } /* * SMPmakeElt() */ double * -SMPmakeElt(SMPmatrix *Matrix, int Row, int Col) +SMPmakeElt( Matrix, Row, Col ) +SMPmatrix *Matrix; +int Row, Col; { - return spGetElement( Matrix, Row, Col ); + return spGetElement( (char *)Matrix, Row, Col ); } /* * SMPcClear() */ void -SMPcClear(SMPmatrix *Matrix) +SMPcClear( Matrix ) +SMPmatrix *Matrix; { - spClear( Matrix ); + spClear( (char *)Matrix ); } /* * SMPclear() */ void -SMPclear(SMPmatrix *Matrix) +SMPclear( Matrix ) +SMPmatrix *Matrix; { - spClear( Matrix ); + spClear( (char *)Matrix ); } -#define NG_IGNORE(x) (void)x - /* * SMPcLUfac() */ /*ARGSUSED*/ int -SMPcLUfac(SMPmatrix *Matrix, double PivTol) +SMPcLUfac( Matrix, PivTol ) +SMPmatrix *Matrix; +double PivTol; { - NG_IGNORE(PivTol); - - spSetComplex( Matrix ); - return spFactor( Matrix ); + spSetComplex( (char *)Matrix ); + return spFactor( (char *)Matrix ); } /* @@ -166,93 +162,97 @@ SMPcLUfac(SMPmatrix *Matrix, double PivTol) */ /*ARGSUSED*/ int -SMPluFac(SMPmatrix *Matrix, double PivTol, double Gmin) +SMPluFac( Matrix, PivTol, Gmin ) +SMPmatrix *Matrix; +double PivTol, Gmin; { - NG_IGNORE(PivTol); - spSetReal( Matrix ); - LoadGmin( Matrix, Gmin ); - return spFactor( Matrix ); + spSetReal( (char *)Matrix ); + LoadGmin( (char *)Matrix, Gmin ); + return spFactor( (char *)Matrix ); } /* * SMPcReorder() */ int -SMPcReorder(SMPmatrix *Matrix, double PivTol, double PivRel, - int *NumSwaps) +SMPcReorder( Matrix, PivTol, PivRel, NumSwaps ) +SMPmatrix *Matrix; +double PivTol, PivRel; +int *NumSwaps; { - *NumSwaps = 1; - spSetComplex( Matrix ); - return spOrderAndFactor( Matrix, NULL, - PivRel, PivTol, YES ); + *NumSwaps = 0; + spSetComplex( (char *)Matrix ); + return spOrderAndFactor( (char *)Matrix, (spREAL*)NULL, + (spREAL)PivRel, (spREAL)PivTol, YES ); } /* * SMPreorder() */ int -SMPreorder(SMPmatrix *Matrix, double PivTol, double PivRel, double Gmin) +SMPreorder( Matrix, PivTol, PivRel, Gmin ) +SMPmatrix *Matrix; +double PivTol, PivRel, Gmin; { - spSetReal( Matrix ); - LoadGmin( Matrix, Gmin ); - return spOrderAndFactor( Matrix, NULL, - PivRel, PivTol, YES ); + spSetComplex( (char *)Matrix ); + LoadGmin( (char *)Matrix, Gmin ); + return spOrderAndFactor( (char *)Matrix, (spREAL*)NULL, + (spREAL)PivRel, (spREAL)PivTol, YES ); } /* * SMPcaSolve() */ void -SMPcaSolve(SMPmatrix *Matrix, double RHS[], double iRHS[], - double Spare[], double iSpare[]) +SMPcaSolve( Matrix, RHS, iRHS, Spare, iSpare) +SMPmatrix *Matrix; +double RHS[], iRHS[], Spare[], iSpare[]; { - NG_IGNORE(iSpare); - NG_IGNORE(Spare); - - spSolveTransposed( Matrix, RHS, RHS, iRHS, iRHS ); + spSolveTransposed( (char *)Matrix, RHS, RHS, iRHS, iRHS ); } /* * SMPcSolve() */ void -SMPcSolve(SMPmatrix *Matrix, double RHS[], double iRHS[], - double Spare[], double iSpare[]) +SMPcSolve( Matrix, RHS, iRHS, Spare, iSpare) +SMPmatrix *Matrix; +double RHS[], iRHS[], Spare[], iSpare[]; { - NG_IGNORE(iSpare); - NG_IGNORE(Spare); - - spSolve( Matrix, RHS, RHS, iRHS, iRHS ); + spSolve( (char *)Matrix, RHS, RHS, iRHS, iRHS ); } /* * SMPsolve() */ void -SMPsolve(SMPmatrix *Matrix, double RHS[], double Spare[]) +SMPsolve( Matrix, RHS, Spare ) +SMPmatrix *Matrix; +double RHS[], Spare[]; { - NG_IGNORE(Spare); - - spSolve( Matrix, RHS, RHS, NULL, NULL ); + spSolve( (char *)Matrix, RHS, RHS, (spREAL*)NULL, (spREAL*)NULL ); } /* * SMPmatSize() */ int -SMPmatSize(SMPmatrix *Matrix) +SMPmatSize( Matrix ) +SMPmatrix *Matrix; { - return spGetSize( Matrix, 1 ); + return spGetSize( (char *)Matrix, 1 ); } /* * SMPnewMatrix() */ int -SMPnewMatrix(SMPmatrix **pMatrix, int size) +SMPnewMatrix( pMatrix, dummy ) +SMPmatrix **pMatrix; +int dummy; { - int Error; - *pMatrix = spCreate( size, 1, &Error ); +int Error; + *pMatrix = (SMPmatrix *)spCreate( 0, 1, &Error ); return Error; } @@ -260,63 +260,67 @@ SMPnewMatrix(SMPmatrix **pMatrix, int size) * SMPdestroy() */ void -SMPdestroy(SMPmatrix *Matrix) +SMPdestroy( Matrix ) +SMPmatrix *Matrix; { - spDestroy( Matrix ); + spDestroy( (char *)Matrix ); } /* * SMPpreOrder() */ int -SMPpreOrder(SMPmatrix *Matrix) +SMPpreOrder( Matrix ) +SMPmatrix *Matrix; { - spMNA_Preorder( Matrix ); - return spError( Matrix ); + spMNA_Preorder( (char *)Matrix ); + return spErrorState( (char *)Matrix ); } /* - * SMPprint() + * SMPprintRHS() */ - void SMPprintRHS(SMPmatrix *Matrix, char *Filename, RealVector RHS, RealVector iRHS) { - spFileVector( Matrix, Filename, RHS, iRHS ); + spFileVector( Matrix, Filename, RHS, iRHS ); } /* * SMPprint() */ - +/*ARGSUSED*/ void -SMPprint(SMPmatrix *Matrix, char *Filename) +SMPprint( Matrix, File ) +SMPmatrix *Matrix; +char *File; { - if (Filename) - spFileMatrix(Matrix, Filename, "Circuit Matrix", 0, 1, 1 ); - else - spPrint( Matrix, 0, 1, 1 ); + spPrint( (char *)Matrix, 0, 1, 1 ); } /* * SMPgetError() */ void -SMPgetError(SMPmatrix *Matrix, int *Col, int *Row) +SMPgetError( Matrix, Col, Row) +SMPmatrix *Matrix; +int *Row, *Col; { - spWhereSingular( Matrix, Row, Col ); + spWhereSingular( (char *)Matrix, Row, Col ); } /* * SMPcProdDiag() - * note: obsolete for Spice3d2 and later */ int -SMPcProdDiag(SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent) +SMPcProdDiag( Matrix, pMantissa, pExponent) +SMPmatrix *Matrix; +SPcomplex *pMantissa; +int *pExponent; { - spDeterminant( Matrix, pExponent, &(pMantissa->real), + spDeterminant( (char *)Matrix, pExponent, &(pMantissa->real), &(pMantissa->imag) ); - return spError( Matrix ); + return spErrorState( (char *)Matrix ); } /* @@ -325,8 +329,8 @@ SMPcProdDiag(SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent) int SMPcDProd(SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent) { - double re, im, x, y, z; - int p; + double re, im, x, y, z; + int p; spDeterminant( Matrix, &p, &re, &im); @@ -347,7 +351,7 @@ SMPcDProd(SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent) y -= x; /* ASSERT - * x = integral part of exponent, y = fraction part of exponent + * x = integral part of exponent, y = fraction part of exponent */ /* Fold in the fractional part */ @@ -363,51 +367,45 @@ SMPcDProd(SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent) /* Re-normalize (re or im may be > 2.0 or both < 1.0 */ if (re != 0.0) { - y = logb(re); - if (im != 0.0) - z = logb(im); - else - z = 0; + y = logb(re); + if (im != 0.0) + z = logb(im); + else + z = 0; } else if (im != 0.0) { - z = logb(im); - y = 0; + z = logb(im); + y = 0; } else { - /* Singular */ - /*printf("10 -> singular\n");*/ - y = 0; - z = 0; + /* Singular */ + /*printf("10 -> singular\n");*/ + y = 0; + z = 0; } #ifdef debug_print printf(" ** renormalize changes = %g,%g\n", y, z); #endif if (y < z) - y = z; + y = z; *pExponent = (int)(x + y); x = scalbn(re, (int) -y); z = scalbn(im, (int) -y); #ifdef debug_print printf(" ** values are: re %g, im %g, y %g, re' %g, im' %g\n", - re, im, y, x, z); + re, im, y, x, z); #endif pMantissa->real = scalbn(re, (int) -y); pMantissa->imag = scalbn(im, (int) -y); #ifdef debug_print printf("Determinant 10->2: (%20g,%20g)^%d\n", pMantissa->real, - pMantissa->imag, *pExponent); + pMantissa->imag, *pExponent); #endif - return spError( Matrix ); + return spErrorState( Matrix ); } - -/* - * The following routines need internal knowledge of the Sparse data - * structures. - */ - /* * LOAD GMIN * @@ -418,47 +416,68 @@ SMPcDProd(SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent) * use of this routine is not recommended. It is included here simply * for compatibility with Spice3. */ - -static void -LoadGmin(SMPmatrix *Matrix, double Gmin) +#include "spDefs.h" +void +LoadGmin( eMatrix, Gmin ) +char *eMatrix; +register double Gmin; { - int I; - ArrayOfElementPtrs Diag; - ElementPtr diag; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I; +register ArrayOfElementPtrs Diag; - /* Begin `LoadGmin'. */ - assert( IS_SPARSE( Matrix ) ); +/* Begin `spLoadGmin'. */ + ASSERT_IS_SPARSE( Matrix ); - if (Gmin != 0.0) { - Diag = Matrix->Diag; - for (I = Matrix->Size; I > 0; I--) { - if ((diag = Diag[I]) != NULL) - diag->Real += Gmin; - } - } + Diag = Matrix->Diag; + for (I = Matrix->Size; I > 0; I--) + Diag[I]->Real += Gmin; return; } + /* * FIND ELEMENT * * This routine finds an element in the matrix by row and column number. * If the element exists, a pointer to it is returned. If not, then NULL - * is returned unless the CreateIfMissing flag is TRUE, in which case a + * is returned unless the CreateIfMissing flag is true, in which case a * pointer to the new element is returned. */ +//SMPelement * +//SMPfindElt( Matrix, Row, Col, CreateIfMissing ) +// +//SMPmatrix *Matrix; +//int Row, Col; +//int CreateIfMissing; +//{ +////MatrixPtr Matrix = (MatrixPtr)eMatrix; +//spREAL *Element = (spREAL *)Matrix->FirstInCol[Col]; +// +///* Begin `SMPfindElt'. */ +// ASSERT_IS_SPARSE( Matrix ); +// if (CreateIfMissing) +// { Element = spcCreateElement( Matrix, Row, Col, +// &Matrix->FirstInRow[Row], +// &Matrix->FirstInCol[Col], NO ); +// } +// else Element = spcFindElement( Matrix, Row, Col ); +// return (SMPelement *)Element; +//} + SMPelement * SMPfindElt(SMPmatrix *Matrix, int Row, int Col, int CreateIfMissing) { ElementPtr Element; /* Begin `SMPfindElt'. */ - assert( IS_SPARSE( Matrix ) ); + ASSERT_IS_SPARSE( Matrix ); Row = Matrix->ExtToIntRowMap[Row]; + Col = Matrix->ExtToIntColMap[Col]; if (Col == -1) @@ -470,7 +489,6 @@ SMPfindElt(SMPmatrix *Matrix, int Row, int Col, int CreateIfMissing) return Element; } -/* XXX The following should probably be implemented in spUtils */ /* * SMPcZeroCol() @@ -478,19 +496,19 @@ SMPfindElt(SMPmatrix *Matrix, int Row, int Col, int CreateIfMissing) int SMPcZeroCol(SMPmatrix *Matrix, int Col) { - ElementPtr Element; + ElementPtr Element; Col = Matrix->ExtToIntColMap[Col]; for (Element = Matrix->FirstInCol[Col]; - Element != NULL; - Element = Element->NextInCol) + Element != NULL; + Element = Element->NextInCol) { - Element->Real = 0.0; - Element->Imag = 0.0; + Element->Real = 0.0; + Element->Imag = 0.0; } - return spError( Matrix ); + return spErrorState( Matrix ); } /* @@ -499,7 +517,7 @@ SMPcZeroCol(SMPmatrix *Matrix, int Col) int SMPcAddCol(SMPmatrix *Matrix, int Accum_Col, int Addend_Col) { - ElementPtr Accum, Addend, *Prev; + ElementPtr Accum, Addend, *Prev; Accum_Col = Matrix->ExtToIntColMap[Accum_Col]; Addend_Col = Matrix->ExtToIntColMap[Addend_Col]; @@ -509,52 +527,29 @@ SMPcAddCol(SMPmatrix *Matrix, int Accum_Col, int Addend_Col) Accum = *Prev; while (Addend != NULL) { - while (Accum && Accum->Row < Addend->Row) { - Prev = &Accum->NextInCol; - Accum = *Prev; - } - if (!Accum || Accum->Row > Addend->Row) { - Accum = spcCreateElement(Matrix, Addend->Row, Accum_Col, Prev, 0); - } - Accum->Real += Addend->Real; - Accum->Imag += Addend->Imag; - Addend = Addend->NextInCol; + while (Accum && Accum->Row < Addend->Row) { + Prev = &Accum->NextInCol; + Accum = *Prev; + } + if (!Accum || Accum->Row > Addend->Row) { + Accum = spcCreateElement(Matrix, Addend->Row, Accum_Col, Prev, 0, 0); + } + Accum->Real += Addend->Real; + Accum->Imag += Addend->Imag; + Addend = Addend->NextInCol; } - return spError( Matrix ); + return spErrorState( Matrix ); } + /* - * SMPzeroRow() + * SMPmultiply() */ -int -SMPzeroRow(SMPmatrix *Matrix, int Row) +void +SMPmultiply(SMPmatrix *Matrix, double *RHS, double *Solution, double *iRHS, double *iSolution) { - ElementPtr Element; - - Row = Matrix->ExtToIntColMap[Row]; - - if (Matrix->RowsLinked == NO) - spcLinkRows(Matrix); - - if (Matrix->PreviousMatrixWasComplex || Matrix->Complex) { - for (Element = Matrix->FirstInRow[Row]; - Element != NULL; - Element = Element->NextInRow) - { - Element->Real = 0.0; - Element->Imag = 0.0; - } - } else { - for (Element = Matrix->FirstInRow[Row]; - Element != NULL; - Element = Element->NextInRow) - { - Element->Real = 0.0; - } - } - - return spError( Matrix ); + spMultiply(Matrix, RHS, Solution, iRHS, iSolution); } /* @@ -565,12 +560,3 @@ SMPconstMult(SMPmatrix *Matrix, double constant) { spConstMult(Matrix, constant); } - -/* - * SMPmultiply() - */ -void -SMPmultiply(SMPmatrix *Matrix, double *RHS, double *Solution, double *iRHS, double *iSolution) -{ - spMultiply(Matrix, RHS, Solution, iRHS, iSolution); -} diff --git a/src/maths/sparse/spsolve.c b/src/maths/sparse/spSolve.c similarity index 54% rename from src/maths/sparse/spsolve.c rename to src/maths/sparse/spSolve.c index e24ebd09d..44d9f4024 100644 --- a/src/maths/sparse/spsolve.c +++ b/src/maths/sparse/spSolve.c @@ -4,11 +4,18 @@ * Author: Advising professor: * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli * UC Berkeley - * + */ +/*! \file * This file contains the forward and backward substitution routines for * the sparse matrix routines. * - * >>> User accessible functions contained in this file: + * Objects that begin with the \a spc prefix are considered private + * and should not be used. + * + * \author + * Kenneth S. Kundert + */ +/* >>> User accessible functions contained in this file: * spSolve * spSolveTransposed * @@ -21,19 +28,12 @@ /* * 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. + * Copyright (c) 1985-2003 + * by Kenneth S. Kundert */ + + /* * IMPORTS * @@ -45,12 +45,12 @@ * spDefs.h * Matrix type and macro definitions for the sparse matrix routines. */ -#include #define spINSIDE_SPARSE -#include "spconfig.h" +#include +#include "spConfig.h" #include "ngspice/spmatrix.h" -#include "spdefs.h" +#include "spDefs.h" @@ -59,10 +59,16 @@ * Function declarations */ +#if spSEPARATED_COMPLEX_VECTORS static void SolveComplexMatrix( MatrixPtr, RealVector, RealVector, RealVector, RealVector ); static void SolveComplexTransposedMatrix( MatrixPtr, RealVector, RealVector, RealVector, RealVector ); +#else +static void SolveComplexMatrix( MatrixPtr, RealVector, RealVector ); +static void SolveComplexTransposedMatrix( MatrixPtr, + RealVector, RealVector ); +#endif @@ -70,35 +76,35 @@ static void SolveComplexTransposedMatrix( MatrixPtr, -/* - * SOLVE MATRIX EQUATION - * +/*! * Performs forward elimination and back substitution to find the - * unknown vector from the RHS vector and factored matrix. This + * unknown vector from the \a RHS vector and factored matrix. This * routine assumes that the pivots are associated with the lower - * triangular (L) matrix and that the diagonal of the upper triangular - * (U) matrix consists of ones. This routine arranges the computation + * triangular matrix and that the diagonal of the upper triangular + * matrix consists of ones. This routine arranges the computation * in different way than is traditionally used in order to exploit the * sparsity of the right-hand side. See the reference in spRevision. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to matrix. - * RHS (RealVector) - * RHS is the input data array, the right hand side. This data is + * \param RHS + * \a RHS is the input data array, the right hand side. This data is * undisturbed and may be reused for other solves. - * Solution (RealVector) - * Solution is the output data array. This routine is constructed such that - * RHS and Solution can be the same array. - * iRHS (RealVector) - * iRHS is the imaginary portion of the input data array, the right + * \param Solution + * \a Solution is the output data array. This routine is constructed + * such that \a RHS and \a Solution can be the same array. + * \param iRHS + * \a iRHS is the imaginary portion of the input data array, the right * hand side. This data is undisturbed and may be reused for other solves. - * iSolution (RealVector) - * iSolution is the imaginary portion of the output data array. This - * routine is constructed such that iRHS and iSolution can be - * the same array. - * - * >>> Local variables: + * This argument is only necessary if matrix is complex and if + * \a spSEPARATED_COMPLEX_VECTOR is set true. + * \param iSolution + * \a iSolution is the imaginary portion of the output data array. This + * routine is constructed such that \a iRHS and \a iSolution can be + * the same array. This argument is only necessary if matrix is complex + * and if \a spSEPARATED_COMPLEX_VECTOR is set true. + */ +/* >>> Local variables: * Intermediate (RealVector) * Temporary storage for use in forward elimination and backward * substitution. Commonly referred to as c, when the LU factorization @@ -119,75 +125,96 @@ static void SolveComplexTransposedMatrix( MatrixPtr, * Size of matrix. Made local to reduce indirection. * Temp (RealNumber) * Temporary storage for entries in arrays. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. */ /*VARARGS3*/ void -spSolve(MatrixPtr Matrix, RealVector RHS, RealVector Solution, - RealVector iRHS, RealVector iSolution) +spSolve( + spMatrix eMatrix, + spREAL RHS[], + spREAL Solution[] +# if spCOMPLEX AND spSEPARATED_COMPLEX_VECTORS + , spREAL iRHS[] + , spREAL iSolution[] +# endif +) { - ElementPtr pElement; - RealVector Intermediate; - RealNumber Temp; - int I, *pExtOrder, Size; - ElementPtr pPivot; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register RealVector Intermediate; +register RealNumber Temp; +register int I, *pExtOrder, Size; +ElementPtr pPivot; +void SolveComplexMatrix(); - /* Begin `spSolve'. */ - assert( IS_VALID(Matrix) && IS_FACTORED(Matrix) ); +/* Begin `spSolve'. */ + ASSERT_IS_SPARSE( Matrix ); + ASSERT_NO_ERRORS( Matrix ); + ASSERT_IS_FACTORED( Matrix ); +#if spCOMPLEX if (Matrix->Complex) - { - SolveComplexMatrix( Matrix, RHS, Solution, iRHS, iSolution ); + { SolveComplexMatrix( Matrix, RHS, Solution IMAG_VECTORS ); return; } +#endif +#if REAL Intermediate = Matrix->Intermediate; Size = Matrix->Size; - /* Initialize Intermediate vector. */ +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET + --RHS; + --Solution; +#endif + +/* Initialize Intermediate vector. */ pExtOrder = &Matrix->IntToExtRowMap[Size]; for (I = Size; I > 0; I--) Intermediate[I] = RHS[*(pExtOrder--)]; - /* Forward elimination. Solves Lc = b.*/ +/* Forward elimination. Solves Lc = b.*/ for (I = 1; I <= Size; I++) - { - - /* This step of the elimination is skipped if Temp equals zero. */ + { +/* This step of the elimination is skipped if Temp equals zero. */ if ((Temp = Intermediate[I]) != 0.0) - { - pPivot = Matrix->Diag[I]; + { pPivot = Matrix->Diag[I]; Intermediate[I] = (Temp *= pPivot->Real); pElement = pPivot->NextInCol; while (pElement != NULL) - { - Intermediate[pElement->Row] -= Temp * pElement->Real; + { Intermediate[pElement->Row] -= Temp * pElement->Real; pElement = pElement->NextInCol; } } } - /* Backward Substitution. Solves Ux = c.*/ +/* Backward Substitution. Solves Ux = c.*/ for (I = Size; I > 0; I--) - { - Temp = Intermediate[I]; + { Temp = Intermediate[I]; pElement = Matrix->Diag[I]->NextInRow; while (pElement != NULL) - { - Temp -= pElement->Real * Intermediate[pElement->Col]; + { Temp -= pElement->Real * Intermediate[pElement->Col]; pElement = pElement->NextInRow; } Intermediate[I] = Temp; } - /* Unscramble Intermediate vector while placing data in to Solution vector. */ +/* Unscramble Intermediate vector while placing data in to Solution vector. */ pExtOrder = &Matrix->IntToExtColMap[Size]; for (I = Size; I > 0; I--) Solution[*(pExtOrder--)] = Intermediate[I]; return; +#endif /* REAL */ } @@ -200,39 +227,37 @@ spSolve(MatrixPtr Matrix, RealVector RHS, RealVector Solution, -/* - * SOLVE COMPLEX MATRIX EQUATION - * +#if spCOMPLEX +/*! * Performs forward elimination and back substitution to find the * unknown vector from the RHS vector and factored matrix. This * routine assumes that the pivots are associated with the lower - * triangular (L) matrix and that the diagonal of the upper triangular - * (U) matrix consists of ones. This routine arranges the computation + * triangular matrix and that the diagonal of the upper triangular + * matrix consists of ones. This routine arranges the computation * in different way than is traditionally used in order to exploit the * sparsity of the right-hand side. See the reference in spRevision. * - * >>> Arguments: - * Matrix (char *) + * \param Matrix * Pointer to matrix. - * RHS (RealVector) + * \param RHS * RHS is the real portion of the input data array, the right hand * side. This data is undisturbed and may be reused for other solves. - * Solution (RealVector) + * \param Solution * Solution is the real portion of the output data array. This routine * is constructed such that RHS and Solution can be the same * array. - * iRHS (RealVector) + * \param iRHS * iRHS is the imaginary portion of the input data array, the right * hand side. This data is undisturbed and may be reused for other solves. - * If spSEPARATED_COMPLEX_VECTOR is set FALSE, there is no need to + * If spSEPARATED_COMPLEX_VECTOR is set false, there is no need to * supply this array. - * iSolution (RealVector) + * \param iSolution * iSolution is the imaginary portion of the output data array. This * routine is constructed such that iRHS and iSolution can be - * the same array. If spSEPARATED_COMPLEX_VECTOR is set FALSE, there is no + * the same array. If spSEPARATED_COMPLEX_VECTOR is set false, there is no * need to supply this array. - * - * >>> Local variables: + */ +/* >>> Local variables: * Intermediate (ComplexVector) * Temporary storage for use in forward elimination and backward * substitution. Commonly referred to as c, when the LU factorization @@ -256,44 +281,68 @@ spSolve(MatrixPtr Matrix, RealVector RHS, RealVector Solution, */ static void -SolveComplexMatrix( MatrixPtr Matrix, RealVector RHS, RealVector Solution , RealVector iRHS, RealVector iSolution ) +SolveComplexMatrix( + MatrixPtr Matrix, + RealVector RHS, + RealVector Solution +# if spSEPARATED_COMPLEX_VECTORS + , RealVector iRHS + , RealVector iSolution +# endif +) { - ElementPtr pElement; - ComplexVector Intermediate; - int I, *pExtOrder, Size; - ElementPtr pPivot; - ComplexNumber Temp; +register ElementPtr pElement; +register ComplexVector Intermediate; +register int I, *pExtOrder, Size; +ElementPtr pPivot; +#if NOT spSEPARATED_COMPLEX_VECTORS +register ComplexVector ExtVector; +#endif +ComplexNumber Temp; - /* Begin `SolveComplexMatrix'. */ +/* Begin `SolveComplexMatrix'. */ Size = Matrix->Size; Intermediate = (ComplexVector)Matrix->Intermediate; - /* Initialize Intermediate vector. */ +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS + --RHS; --iRHS; + --Solution; --iSolution; +#else + RHS -= 2; Solution -= 2; +#endif +#endif + +/* Initialize Intermediate vector. */ pExtOrder = &Matrix->IntToExtRowMap[Size]; +#if spSEPARATED_COMPLEX_VECTORS for (I = Size; I > 0; I--) - { - Intermediate[I].Real = RHS[*(pExtOrder)]; + { Intermediate[I].Real = RHS[*(pExtOrder)]; Intermediate[I].Imag = iRHS[*(pExtOrder--)]; } +#else + ExtVector = (ComplexVector)RHS; + for (I = Size; I > 0; I--) + Intermediate[I] = ExtVector[*(pExtOrder--)]; +#endif - /* Forward substitution. Solves Lc = b.*/ +/* Forward substitution. Solves Lc = b.*/ for (I = 1; I <= Size; I++) - { - Temp = Intermediate[I]; + { Temp = Intermediate[I]; - /* This step of the substitution is skipped if Temp equals zero. */ - if ((Temp.Real != 0.0) || (Temp.Imag != 0.0)) - { - pPivot = Matrix->Diag[I]; - /* Cmplx expr: Temp *= (1.0 / Pivot). */ +/* This step of the substitution is skipped if Temp equals zero. */ + if ((Temp.Real != 0.0) OR (Temp.Imag != 0.0)) + { pPivot = Matrix->Diag[I]; +/* Cmplx expr: Temp *= (1.0 / Pivot). */ CMPLX_MULT_ASSIGN(Temp, *pPivot); Intermediate[I] = Temp; pElement = pPivot->NextInCol; while (pElement != NULL) { - /* Cmplx expr: Intermediate[Element->Row] -= Temp * *Element. */ +/* Cmplx expr: Intermediate[Element->Row] -= Temp * *Element. */ CMPLX_MULT_SUBT_ASSIGN(Intermediate[pElement->Row], Temp, *pElement); pElement = pElement->NextInCol; @@ -301,32 +350,37 @@ SolveComplexMatrix( MatrixPtr Matrix, RealVector RHS, RealVector Solution , Real } } - /* Backward Substitution. Solves Ux = c.*/ +/* Backward Substitution. Solves Ux = c.*/ for (I = Size; I > 0; I--) - { - Temp = Intermediate[I]; + { Temp = Intermediate[I]; pElement = Matrix->Diag[I]->NextInRow; while (pElement != NULL) { - /* Cmplx expr: Temp -= *Element * Intermediate[Element->Col]. */ +/* Cmplx expr: Temp -= *Element * Intermediate[Element->Col]. */ CMPLX_MULT_SUBT_ASSIGN(Temp, *pElement,Intermediate[pElement->Col]); pElement = pElement->NextInRow; } Intermediate[I] = Temp; } - /* Unscramble Intermediate vector while placing data in to Solution vector. */ +/* Unscramble Intermediate vector while placing data in to Solution vector. */ pExtOrder = &Matrix->IntToExtColMap[Size]; +#if spSEPARATED_COMPLEX_VECTORS for (I = Size; I > 0; I--) - { - Solution[*(pExtOrder)] = Intermediate[I].Real; + { Solution[*(pExtOrder)] = Intermediate[I].Real; iSolution[*(pExtOrder--)] = Intermediate[I].Imag; } +#else + ExtVector = (ComplexVector)Solution; + for (I = Size; I > 0; I--) + ExtVector[*(pExtOrder--)] = Intermediate[I]; +#endif return; } +#endif /* spCOMPLEX */ @@ -342,38 +396,35 @@ SolveComplexMatrix( MatrixPtr Matrix, RealVector RHS, RealVector Solution , Real #if TRANSPOSE -/* - * SOLVE TRANSPOSED MATRIX EQUATION - * +/*! * Performs forward elimination and back substitution to find the * unknown vector from the RHS vector and transposed factored * matrix. This routine is useful when performing sensitivity analysis * on a circuit using the adjoint method. This routine assumes that * the pivots are associated with the untransposed lower triangular - * (L) matrix and that the diagonal of the untransposed upper - * triangular (U) matrix consists of ones. + * matrix and that the diagonal of the untransposed upper + * triangular matrix consists of ones. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to matrix. - * RHS (RealVector) - * RHS is the input data array, the right hand side. This data is + * \param RHS + * \a RHS is the input data array, the right hand side. This data is * undisturbed and may be reused for other solves. - * Solution (RealVector) - * Solution is the output data array. This routine is constructed such that - * RHS and Solution can be the same array. - * iRHS (RealVector) - * iRHS is the imaginary portion of the input data array, the right + * \param Solution + * \a Solution is the output data array. This routine is constructed + * such that \a RHS and \a Solution can be the same array. + * \param iRHS + * \a iRHS is the imaginary portion of the input data array, the right * hand side. This data is undisturbed and may be reused for other solves. - * If spSEPARATED_COMPLEX_VECTOR is set FALSE, or if matrix is real, there - * is no need to supply this array. - * iSolution (RealVector) - * iSolution is the imaginary portion of the output data array. This - * routine is constructed such that iRHS and iSolution can be - * the same array. If spSEPARATED_COMPLEX_VECTOR is set FALSE, or if + * If \a spSEPARATED_COMPLEX_VECTOR is set false, or if matrix is real, + * there is no need to supply this array. + * \param iSolution + * \a iSolution is the imaginary portion of the output data array. This + * routine is constructed such that \a iRHS and \a iSolution can be + * the same array. If \a spSEPARATED_COMPLEX_VECTOR is set false, or if * matrix is real, there is no need to supply this array. - * - * >>> Local variables: + */ +/* >>> Local variables: * Intermediate (RealVector) * Temporary storage for use in forward elimination and backward * substitution. Commonly referred to as c, when the LU factorization @@ -399,70 +450,84 @@ SolveComplexMatrix( MatrixPtr Matrix, RealVector RHS, RealVector Solution , Real /*VARARGS3*/ void -spSolveTransposed(MatrixPtr Matrix, RealVector RHS, RealVector Solution, - RealVector iRHS, RealVector iSolution) +spSolveTransposed( + spMatrix eMatrix, + spREAL RHS[], + spREAL Solution[] +# if spCOMPLEX AND spSEPARATED_COMPLEX_VECTORS + , spREAL iRHS[] + , spREAL iSolution[] +# endif +) { - ElementPtr pElement; - RealVector Intermediate; - int I, *pExtOrder, Size; - ElementPtr pPivot; - RealNumber Temp; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register RealVector Intermediate; +register int I, *pExtOrder, Size; +ElementPtr pPivot; +RealNumber Temp; +void SolveComplexTransposedMatrix(); - /* Begin `spSolveTransposed'. */ - assert( IS_VALID(Matrix) && IS_FACTORED(Matrix) ); +/* Begin `spSolveTransposed'. */ + ASSERT_IS_SPARSE( Matrix ); + ASSERT_NO_ERRORS( Matrix ); + ASSERT_IS_FACTORED( Matrix ); +#if spCOMPLEX if (Matrix->Complex) - { - SolveComplexTransposedMatrix( Matrix, RHS, Solution , iRHS, iSolution ); + { SolveComplexTransposedMatrix( Matrix, RHS, Solution IMAG_VECTORS ); return; } +#endif +#if REAL Size = Matrix->Size; Intermediate = Matrix->Intermediate; - /* Initialize Intermediate vector. */ +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET + --RHS; + --Solution; +#endif + +/* Initialize Intermediate vector. */ pExtOrder = &Matrix->IntToExtColMap[Size]; for (I = Size; I > 0; I--) Intermediate[I] = RHS[*(pExtOrder--)]; - /* Forward elimination. */ +/* Forward elimination. */ for (I = 1; I <= Size; I++) - { - - /* This step of the elimination is skipped if Temp equals zero. */ + { +/* This step of the elimination is skipped if Temp equals zero. */ if ((Temp = Intermediate[I]) != 0.0) - { - pElement = Matrix->Diag[I]->NextInRow; + { pElement = Matrix->Diag[I]->NextInRow; while (pElement != NULL) - { - Intermediate[pElement->Col] -= Temp * pElement->Real; + { Intermediate[pElement->Col] -= Temp * pElement->Real; pElement = pElement->NextInRow; } } } - /* Backward Substitution. */ +/* Backward Substitution. */ for (I = Size; I > 0; I--) - { - pPivot = Matrix->Diag[I]; + { pPivot = Matrix->Diag[I]; Temp = Intermediate[I]; pElement = pPivot->NextInCol; while (pElement != NULL) - { - Temp -= pElement->Real * Intermediate[pElement->Row]; + { Temp -= pElement->Real * Intermediate[pElement->Row]; pElement = pElement->NextInCol; } Intermediate[I] = Temp * pPivot->Real; } - /* Unscramble Intermediate vector while placing data in to - Solution vector. */ +/* Unscramble Intermediate vector while placing data in to Solution vector. */ pExtOrder = &Matrix->IntToExtRowMap[Size]; for (I = Size; I > 0; I--) Solution[*(pExtOrder--)] = Intermediate[I]; return; +#endif /* REAL */ } #endif /* TRANSPOSE */ @@ -475,38 +540,40 @@ spSolveTransposed(MatrixPtr Matrix, RealVector RHS, RealVector Solution, -#if TRANSPOSE -/* - * SOLVE COMPLEX TRANSPOSED MATRIX EQUATION - * +#if TRANSPOSE AND spCOMPLEX +/*! * Performs forward elimination and back substitution to find the * unknown vector from the RHS vector and transposed factored * matrix. This routine is useful when performing sensitivity analysis * on a circuit using the adjoint method. This routine assumes that * the pivots are associated with the untransposed lower triangular - * (L) matrix and that the diagonal of the untransposed upper - * triangular (U) matrix consists of ones. + * matrix and that the diagonal of the untransposed upper + * triangular matrix consists of ones. * - * >>> Arguments: - * Matrix (char *) + * \param Matrix * Pointer to matrix. - * RHS (RealVector) - * RHS is the input data array, the right hand + * \param RHS + * \a RHS is the input data array, the right hand * side. This data is undisturbed and may be reused for other solves. - * This vector is only the real portion if the matrix is complex. - * Solution (RealVector) - * Solution is the real portion of the output data array. This routine - * is constructed such that RHS and Solution can be the same array. - * This vector is only the real portion if the matrix is complex. - * iRHS (RealVector) - * iRHS is the imaginary portion of the input data array, the right + * This vector is only the real portion if the matrix is complex and + * \a spSEPARATED_COMPLEX_VECTORS is set true. + * \param Solution + * \a Solution is the real portion of the output data array. This routine + * is constructed such that \a RHS and \a Solution can be the same array. + * This vector is only the real portion if the matrix is complex and + * \a spSEPARATED_COMPLEX_VECTORS is set true. + * \param iRHS + * \a iRHS is the imaginary portion of the input data array, the right * hand side. This data is undisturbed and may be reused for other solves. - * iSolution (RealVector) - * iSolution is the imaginary portion of the output data array. This - * routine is constructed such that iRHS and iSolution can be - * the same array. - * - * >>> Local variables: + * If either \a spCOMPLEX or \a spSEPARATED_COMPLEX_VECTOR is set false, + * there is no need to supply this array. + * \param iSolution + * \a iSolution is the imaginary portion of the output data array. This + * routine is constructed such that \a iRHS and \a iSolution can be + * the same array. If \a spCOMPLEX or \a spSEPARATED_COMPLEX_VECTOR is set + * false, there is no need to supply this array. + */ +/* >>> Local variables: * Intermediate (ComplexVector) * Temporary storage for use in forward elimination and backward * substitution. Commonly referred to as c, when the LU factorization @@ -530,40 +597,64 @@ spSolveTransposed(MatrixPtr Matrix, RealVector RHS, RealVector Solution, */ static void -SolveComplexTransposedMatrix(MatrixPtr Matrix, RealVector RHS, RealVector Solution , RealVector iRHS, RealVector iSolution ) +SolveComplexTransposedMatrix( + MatrixPtr Matrix, + RealVector RHS, + RealVector Solution +# if spSEPARATED_COMPLEX_VECTORS + , RealVector iRHS + , RealVector iSolution +# endif +) { - ElementPtr pElement; - ComplexVector Intermediate; - int I, *pExtOrder, Size; - ElementPtr pPivot; - ComplexNumber Temp; +register ElementPtr pElement; +register ComplexVector Intermediate; +register int I, *pExtOrder, Size; +#if NOT spSEPARATED_COMPLEX_VECTORS +register ComplexVector ExtVector; +#endif +ElementPtr pPivot; +ComplexNumber Temp; - /* Begin `SolveComplexTransposedMatrix'. */ +/* Begin `SolveComplexTransposedMatrix'. */ Size = Matrix->Size; Intermediate = (ComplexVector)Matrix->Intermediate; - /* Initialize Intermediate vector. */ +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS + --RHS; --iRHS; + --Solution; --iSolution; +#else + RHS -= 2; Solution -= 2; +#endif +#endif + +/* Initialize Intermediate vector. */ pExtOrder = &Matrix->IntToExtColMap[Size]; +#if spSEPARATED_COMPLEX_VECTORS for (I = Size; I > 0; I--) - { - Intermediate[I].Real = RHS[*(pExtOrder)]; + { Intermediate[I].Real = RHS[*(pExtOrder)]; Intermediate[I].Imag = iRHS[*(pExtOrder--)]; } +#else + ExtVector = (ComplexVector)RHS; + for (I = Size; I > 0; I--) + Intermediate[I] = ExtVector[*(pExtOrder--)]; +#endif - /* Forward elimination. */ +/* Forward elimination. */ for (I = 1; I <= Size; I++) - { - Temp = Intermediate[I]; + { Temp = Intermediate[I]; - /* This step of the elimination is skipped if Temp equals zero. */ - if ((Temp.Real != 0.0) || (Temp.Imag != 0.0)) - { - pElement = Matrix->Diag[I]->NextInRow; +/* This step of the elimination is skipped if Temp equals zero. */ + if ((Temp.Real != 0.0) OR (Temp.Imag != 0.0)) + { pElement = Matrix->Diag[I]->NextInRow; while (pElement != NULL) { - /* Cmplx expr: Intermediate[Element->Col] -= Temp * *Element. */ +/* Cmplx expr: Intermediate[Element->Col] -= Temp * *Element. */ CMPLX_MULT_SUBT_ASSIGN( Intermediate[pElement->Col], Temp, *pElement); pElement = pElement->NextInRow; @@ -571,34 +662,37 @@ SolveComplexTransposedMatrix(MatrixPtr Matrix, RealVector RHS, RealVector Soluti } } - /* Backward Substitution. */ +/* Backward Substitution. */ for (I = Size; I > 0; I--) - { - pPivot = Matrix->Diag[I]; + { pPivot = Matrix->Diag[I]; Temp = Intermediate[I]; pElement = pPivot->NextInCol; while (pElement != NULL) { - /* Cmplx expr: Temp -= Intermediate[Element->Row] * *Element. */ +/* Cmplx expr: Temp -= Intermediate[Element->Row] * *Element. */ CMPLX_MULT_SUBT_ASSIGN(Temp,Intermediate[pElement->Row],*pElement); pElement = pElement->NextInCol; } - /* Cmplx expr: Intermediate = Temp * (1.0 / *pPivot). */ +/* Cmplx expr: Intermediate = Temp * (1.0 / *pPivot). */ CMPLX_MULT(Intermediate[I], Temp, *pPivot); } - /* Unscramble Intermediate vector while placing data in to - Solution vector. */ +/* Unscramble Intermediate vector while placing data in to Solution vector. */ pExtOrder = &Matrix->IntToExtRowMap[Size]; +#if spSEPARATED_COMPLEX_VECTORS for (I = Size; I > 0; I--) - { - Solution[*(pExtOrder)] = Intermediate[I].Real; + { Solution[*(pExtOrder)] = Intermediate[I].Real; iSolution[*(pExtOrder--)] = Intermediate[I].Imag; } +#else + ExtVector = (ComplexVector)Solution; + for (I = Size; I > 0; I--) + ExtVector[*(pExtOrder--)] = Intermediate[I]; +#endif return; } -#endif /* TRANSPOSE */ +#endif /* TRANSPOSE AND spCOMPLEX */ diff --git a/src/maths/sparse/sputils.c b/src/maths/sparse/spUtils.c similarity index 59% rename from src/maths/sparse/sputils.c rename to src/maths/sparse/spUtils.c index 32e7e9f5b..6dd2f978f 100644 --- a/src/maths/sparse/sputils.c +++ b/src/maths/sparse/spUtils.c @@ -4,16 +4,23 @@ * Author: Advising professor: * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli * UC Berkeley - * + */ +/*! \file * This file contains various optional utility routines. * - * >>> User accessible functions contained in this file: + * Objects that begin with the \a spc prefix are considered private + * and should not be used. + * + * \author + * Kenneth S. Kundert + */ +/* >>> User accessible functions contained in this file: * spMNA_Preorder * spScale * spMultiply * spMultTransposed * spDeterminant - * spStripFills + * spStrip * spDeleteRowAndCol * spPseudoCondition * spCondition @@ -34,19 +41,11 @@ /* * 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. + * Copyright (c) 1985-2003 by Kenneth S. Kundert */ + + /* * IMPORTS * @@ -58,35 +57,50 @@ * spDefs.h * Matrix type and macro definitions for the sparse matrix routines. */ -#include -#include #define spINSIDE_SPARSE -#include "spconfig.h" +#include +#include "spConfig.h" #include "ngspice/spmatrix.h" -#include "spdefs.h" +#include "spDefs.h" -/* Function declarations */ +/* + * Function declarations + */ static int CountTwins( MatrixPtr, int, ElementPtr*, ElementPtr* ); static void SwapCols( MatrixPtr, ElementPtr, ElementPtr ); -static void ComplexMatrixMultiply( MatrixPtr, RealVector, RealVector, - RealVector, RealVector ); -static void ComplexTransposedMatrixMultiply( MatrixPtr, RealVector, RealVector, - RealVector, RealVector); +#if spCOMPLEX AND SCALING +static void ScaleComplexMatrix( MatrixPtr, RealVector, RealVector ); +#endif +#if spSEPARATED_COMPLEX_VECTORS +static void ComplexMatrixMultiply( MatrixPtr, + RealVector, RealVector, RealVector, RealVector ); +static void ComplexTransposedMatrixMultiply( MatrixPtr, + RealVector, RealVector, RealVector, RealVector ); +#else +static void ComplexMatrixMultiply( MatrixPtr, + RealVector, RealVector ); +static void ComplexTransposedMatrixMultiply( MatrixPtr, + RealVector, RealVector ); +#endif +#if CONDITION +#if spCOMPLEX +static RealNumber ComplexCondition( MatrixPtr, RealNumber, int* ); +#endif +#endif + #if MODIFIED_NODAL -/* - * PREORDER MODIFIED NODE ADMITTANCE MATRIX TO REMOVE ZEROS FROM DIAGONAL - * +/*! * This routine massages modified node admittance matrices to remove * zeros from the diagonal. It takes advantage of the fact that the * row and column associated with a zero diagonal usually have @@ -100,44 +114,50 @@ static void ComplexTransposedMatrixMultiply( MatrixPtr, RealVector, RealVector, * * This routine exploits the fact that the structural ones are placed * in the matrix in symmetric twins. For example, the stamps for - * grounded and a floating voltage sources are + * grounded and a floating voltage sources are \code * grounded: floating: * [ x x 1 ] [ x x 1 ] * [ x x ] [ x x -1 ] * [ 1 ] [ 1 -1 ] + * \endcode * Notice for the grounded source, there is one set of twins, and for * the floating, there are two sets. We remove the zero from the diagonal - * by swapping the rows associated with a set of twins. For example: + * by swapping the rows associated with a set of twins. For example: \code * grounded: floating 1: floating 2: * [ 1 ] [ 1 -1 ] [ x x 1 ] * [ x x ] [ x x -1 ] [ 1 -1 ] * [ x x 1 ] [ x x 1 ] [ x x -1 ] + * \endcode * * It is important to deal with any zero diagonals that only have one * set of twins before dealing with those that have more than one because * swapping row destroys the symmetry of any twins in the rows being - * swapped, which may limit future moves. Consider + * swapped, which may limit future moves. Consider \code * [ x x 1 ] * [ x x -1 1 ] * [ 1 -1 ] * [ 1 ] + * \endcode * There is one set of twins for diagonal 4 and two for diagonal 3. - * Dealing with diagonal 4 first requires swapping rows 2 and 4. + * Dealing with diagonal 4 first requires swapping rows 2 and 4. \code * [ x x 1 ] * [ 1 ] * [ 1 -1 ] * [ x x -1 1 ] - * We can now deal with diagonal 3 by swapping rows 1 and 3. + * \endcode + * We can now deal with diagonal 3 by swapping rows 1 and 3. \code * [ 1 -1 ] * [ 1 ] * [ x x 1 ] * [ x x -1 1 ] + * \endcode * And we are done, there are no zeros left on the diagonal. However, if - * we originally dealt with diagonal 3 first, we could swap rows 2 and 3 + * we originally dealt with diagonal 3 first, we could swap rows 2 and 3 \code * [ x x 1 ] * [ 1 -1 ] * [ x x -1 1 ] * [ 1 ] + * \endcode * Diagonal 4 no longer has a symmetric twin and we cannot continue. * * So we always take care of lone twins first. When none remain, we @@ -150,11 +170,10 @@ static void ComplexTransposedMatrixMultiply( MatrixPtr, RealVector, RealVector, * The algorithm used in this function was developed by Ken Kundert and * Tom Quarles. * - * >>> Arguments: - * Matrix (char *) + * \param * eMatrix * Pointer to the matrix to be preordered. - * - * >>> Local variables; + */ +/* >>> Local variables; * J (int) * Column with zero diagonal being currently considered. * pTwin1 (ElementPtr) @@ -162,64 +181,59 @@ static void ComplexTransposedMatrixMultiply( MatrixPtr, RealVector, RealVector, * pTwin2 (ElementPtr) * Pointer to the twin found in the row belonging to the zero diagonal. * belonging to the zero diagonal. - * AnotherPassNeeded (int) + * AnotherPassNeeded (BOOLEAN) * Flag indicating that at least one zero diagonal with symmetric twins * remain. * StartAt (int) * Column number of first zero diagonal with symmetric twins. - * Swapped (int) + * Swapped (BOOLEAN) * Flag indicating that columns were swapped on this pass. * Twins (int) * Number of symmetric twins corresponding to current zero diagonal. */ void -spMNA_Preorder(MatrixPtr Matrix) +spMNA_Preorder( spMatrix eMatrix ) { - int J, Size; - ElementPtr pTwin1, pTwin2; - int Twins, StartAt = 1; - int Swapped, AnotherPassNeeded; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int J, Size; +ElementPtr pTwin1, pTwin2; +int Twins, StartAt = 1; +BOOLEAN Swapped, AnotherPassNeeded; - /* Begin `spMNA_Preorder'. */ - assert( IS_VALID(Matrix) && !Matrix->Factored ); +/* Begin `spMNA_Preorder'. */ + ASSERT_IS_SPARSE( Matrix ); + ASSERT_NO_ERRORS( Matrix ); + ASSERT_IS_NOT_FACTORED( Matrix ); if (Matrix->RowsLinked) return; Size = Matrix->Size; Matrix->Reordered = YES; do - { - AnotherPassNeeded = Swapped = NO; + { AnotherPassNeeded = Swapped = NO; - /* Search for zero diagonals with lone twins. */ +/* Search for zero diagonals with lone twins. */ for (J = StartAt; J <= Size; J++) - { - if (Matrix->Diag[J] == NULL) - { - Twins = CountTwins( Matrix, J, &pTwin1, &pTwin2 ); + { if (Matrix->Diag[J] == NULL) + { Twins = CountTwins( Matrix, J, &pTwin1, &pTwin2 ); if (Twins == 1) - { - /* Lone twins found, swap rows. */ + { /* Lone twins found, swap rows. */ SwapCols( Matrix, pTwin1, pTwin2 ); Swapped = YES; } - else if ((Twins > 1) && !AnotherPassNeeded) - { - AnotherPassNeeded = YES; + else if ((Twins > 1) AND NOT AnotherPassNeeded) + { AnotherPassNeeded = YES; StartAt = J; } } } - /* All lone twins are gone, look for zero diagonals with multiple twins. */ +/* All lone twins are gone, look for zero diagonals with multiple twins. */ if (AnotherPassNeeded) - { - for (J = StartAt; !Swapped && (J <= Size); J++) - { - if (Matrix->Diag[J] == NULL) - { - Twins = CountTwins( Matrix, J, &pTwin1, &pTwin2 ); + { for (J = StartAt; NOT Swapped AND (J <= Size); J++) + { if (Matrix->Diag[J] == NULL) + { Twins = CountTwins( Matrix, J, &pTwin1, &pTwin2 ); SwapCols( Matrix, pTwin1, pTwin2 ); Swapped = YES; } @@ -241,25 +255,27 @@ spMNA_Preorder(MatrixPtr Matrix) */ static int -CountTwins( MatrixPtr Matrix, int Col, ElementPtr *ppTwin1, ElementPtr *ppTwin2 ) +CountTwins( + MatrixPtr Matrix, + int Col, + ElementPtr *ppTwin1, + ElementPtr *ppTwin2 +) { - int Row, Twins = 0; - ElementPtr pTwin1, pTwin2; +int Row, Twins = 0; +ElementPtr pTwin1, pTwin2; - /* Begin `CountTwins'. */ +/* Begin `CountTwins'. */ pTwin1 = Matrix->FirstInCol[Col]; while (pTwin1 != NULL) - { - if (ABS(pTwin1->Real) == 1.0) - { - Row = pTwin1->Row; + { if (ABS(pTwin1->Real) == 1.0) + { Row = pTwin1->Row; pTwin2 = Matrix->FirstInCol[Row]; - while ((pTwin2 != NULL) && (pTwin2->Row != Col)) + while ((pTwin2 != NULL) AND (pTwin2->Row != Col)) pTwin2 = pTwin2->NextInCol; - if ((pTwin2 != NULL) && (ABS(pTwin2->Real) == 1.0)) - { - /* Found symmetric twins. */ + if ((pTwin2 != NULL) AND (ABS(pTwin2->Real) == 1.0)) + { /* Found symmetric twins. */ if (++Twins >= 2) return Twins; (*ppTwin1 = pTwin1)->Col = Col; (*ppTwin2 = pTwin2)->Col = Row; @@ -281,11 +297,15 @@ CountTwins( MatrixPtr Matrix, int Col, ElementPtr *ppTwin1, ElementPtr *ppTwin2 */ static void -SwapCols( MatrixPtr Matrix, ElementPtr pTwin1, ElementPtr pTwin2 ) +SwapCols( + MatrixPtr Matrix, + ElementPtr pTwin1, + ElementPtr pTwin2 +) { - int Col1 = pTwin1->Col, Col2 = pTwin2->Col; +int Col1 = pTwin1->Col, Col2 = pTwin2->Col; - /* Begin `SwapCols'. */ +/* Begin `SwapCols'. */ SWAP (ElementPtr, Matrix->FirstInCol[Col1], Matrix->FirstInCol[Col2]); SWAP (int, Matrix->IntToExtColMap[Col1], Matrix->IntToExtColMap[Col2]); @@ -296,7 +316,7 @@ SwapCols( MatrixPtr Matrix, ElementPtr pTwin1, ElementPtr pTwin2 ) Matrix->Diag[Col1] = pTwin2; Matrix->Diag[Col2] = pTwin1; - Matrix->NumberOfInterchangesIsOdd = !Matrix->NumberOfInterchangesIsOdd; + Matrix->NumberOfInterchangesIsOdd = NOT Matrix->NumberOfInterchangesIsOdd; return; } #endif /* MODIFIED_NODAL */ @@ -310,9 +330,7 @@ SwapCols( MatrixPtr Matrix, ElementPtr pTwin1, ElementPtr pTwin2 ) #if SCALING -/* - * SCALE MATRIX - * +/*! * This function scales the matrix to enhance the possibility of * finding a good pivoting order. Note that scaling enhances accuracy * of the solution only if it affects the pivoting order, so it makes @@ -342,19 +360,18 @@ SwapCols( MatrixPtr Matrix, ElementPtr pTwin1, ElementPtr pTwin2 ) * pivoting order, and then throw away the matrix. Subsequent * factorizations, performed with spFactor(), will not need to have * the RHS and Solution vectors descaled. Lastly, this function - * should not be executed before the function spMNA_Preorder. + * should not be executed before the function spMNA_Preorder(). * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to the matrix to be scaled. - * SolutionScaleFactors (RealVector) + * \param SolutionScaleFactors * The array of Solution scale factors. These factors scale the columns. * All scale factors are real valued. - * RHS_ScaleFactors (RealVector) + * \param RHS_ScaleFactors * The array of RHS scale factors. These factors scale the rows. * All scale factors are real valued. - * - * >>> Local variables: + */ +/* >>> Local variables: * lSize (int) * Local version of the size of the matrix. * pElement (ElementPtr) @@ -367,58 +384,68 @@ SwapCols( MatrixPtr Matrix, ElementPtr pTwin1, ElementPtr pTwin2 ) */ void -spScale(MatrixPtr Matrix, RealVector RHS_ScaleFactors, RealVector SolutionScaleFactors) +spScale( + spMatrix eMatrix, + spREAL RHS_ScaleFactors[], + spREAL SolutionScaleFactors[] +) { - ElementPtr pElement; - int I, lSize, *pExtOrder; - RealNumber ScaleFactor; - void ScaleComplexMatrix(); +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register int I, lSize, *pExtOrder; +RealNumber ScaleFactor; +//void ScaleComplexMatrix(); - /* Begin `spScale'. */ - assert( IS_VALID(Matrix) && !Matrix->Factored ); - if (!Matrix->RowsLinked) spcLinkRows( Matrix ); +/* Begin `spScale'. */ + ASSERT_IS_SPARSE( Matrix ); + ASSERT_NO_ERRORS( Matrix ); + ASSERT_IS_NOT_FACTORED( Matrix ); + if (NOT Matrix->RowsLinked) spcLinkRows( Matrix ); +#if spCOMPLEX if (Matrix->Complex) - { - ScaleComplexMatrix( Matrix, RHS_ScaleFactors, SolutionScaleFactors ); + { ScaleComplexMatrix( Matrix, RHS_ScaleFactors, SolutionScaleFactors ); return; } +#endif +#if REAL lSize = Matrix->Size; - /* Scale Rows */ +/* Correct pointers to arrays for ARRAY_OFFSET */ +#if NOT ARRAY_OFFSET + --RHS_ScaleFactors; + --SolutionScaleFactors; +#endif + +/* Scale Rows */ pExtOrder = &Matrix->IntToExtRowMap[1]; for (I = 1; I <= lSize; I++) - { - if ((ScaleFactor = RHS_ScaleFactors[*(pExtOrder++)]) != 1.0) - { - pElement = Matrix->FirstInRow[I]; + { if ((ScaleFactor = RHS_ScaleFactors[*(pExtOrder++)]) != 1.0) + { pElement = Matrix->FirstInRow[I]; while (pElement != NULL) - { - pElement->Real *= ScaleFactor; + { pElement->Real *= ScaleFactor; pElement = pElement->NextInRow; } } } - /* Scale Columns */ +/* Scale Columns */ pExtOrder = &Matrix->IntToExtColMap[1]; for (I = 1; I <= lSize; I++) - { - if ((ScaleFactor = SolutionScaleFactors[*(pExtOrder++)]) != 1.0) - { - pElement = Matrix->FirstInCol[I]; + { if ((ScaleFactor = SolutionScaleFactors[*(pExtOrder++)]) != 1.0) + { pElement = Matrix->FirstInCol[I]; while (pElement != NULL) - { - pElement->Real *= ScaleFactor; + { pElement->Real *= ScaleFactor; pElement = pElement->NextInCol; } } } return; +#endif /* REAL */ } #endif /* SCALING */ @@ -430,7 +457,7 @@ spScale(MatrixPtr Matrix, RealVector RHS_ScaleFactors, RealVector SolutionScaleF -#if SCALING +#if spCOMPLEX AND SCALING /* * SCALE COMPLEX MATRIX * @@ -488,46 +515,47 @@ spScale(MatrixPtr Matrix, RealVector RHS_ScaleFactors, RealVector SolutionScaleF */ static void -ScaleComplexMatrix( Matrix, RHS_ScaleFactors, SolutionScaleFactors ) - -MatrixPtr Matrix; - RealVector RHS_ScaleFactors, SolutionScaleFactors; +ScaleComplexMatrix( + MatrixPtr Matrix, + register RealVector RHS_ScaleFactors, + register RealVector SolutionScaleFactors +) { - ElementPtr pElement; - int I, lSize, *pExtOrder; - RealNumber ScaleFactor; +register ElementPtr pElement; +register int I, lSize, *pExtOrder; +RealNumber ScaleFactor; - /* Begin `ScaleComplexMatrix'. */ +/* Begin `ScaleComplexMatrix'. */ lSize = Matrix->Size; - /* Scale Rows */ +/* Correct pointers to arrays for ARRAY_OFFSET */ +#if NOT ARRAY_OFFSET + --RHS_ScaleFactors; + --SolutionScaleFactors; +#endif + +/* Scale Rows */ pExtOrder = &Matrix->IntToExtRowMap[1]; for (I = 1; I <= lSize; I++) - { - if ((ScaleFactor = RHS_ScaleFactors[*(pExtOrder++)]) != 1.0) - { - pElement = Matrix->FirstInRow[I]; + { if ((ScaleFactor = RHS_ScaleFactors[*(pExtOrder++)]) != 1.0) + { pElement = Matrix->FirstInRow[I]; while (pElement != NULL) - { - pElement->Real *= ScaleFactor; + { pElement->Real *= ScaleFactor; pElement->Imag *= ScaleFactor; pElement = pElement->NextInRow; } } } - /* Scale Columns */ +/* Scale Columns */ pExtOrder = &Matrix->IntToExtColMap[1]; for (I = 1; I <= lSize; I++) - { - if ((ScaleFactor = SolutionScaleFactors[*(pExtOrder++)]) != 1.0) - { - pElement = Matrix->FirstInCol[I]; + { if ((ScaleFactor = SolutionScaleFactors[*(pExtOrder++)]) != 1.0) + { pElement = Matrix->FirstInCol[I]; while (pElement != NULL) - { - pElement->Real *= ScaleFactor; + { pElement->Real *= ScaleFactor; pElement->Imag *= ScaleFactor; pElement = pElement->NextInCol; } @@ -535,7 +563,7 @@ MatrixPtr Matrix; } return; } -#endif /* SCALING */ +#endif /* SCALING AND spCOMPLEX */ @@ -545,52 +573,69 @@ MatrixPtr Matrix; #if MULTIPLICATION -/* - * MATRIX MULTIPLICATION - * +/*! * Multiplies matrix by solution vector to find source vector. * Assumes matrix has not been factored. This routine can be used * as a test to see if solutions are correct. It should not be used * before spMNA_Preorder(). * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to the matrix. - * RHS (RealVector) + * \param RHS * RHS is the right hand side. This is what is being solved for. - * Solution (RealVector) + * \param Solution * Solution is the vector being multiplied by the matrix. - * iRHS (RealVector) + * \param iRHS * iRHS is the imaginary portion of the right hand side. This is - * what is being solved for. - * iSolution (RealVector) + * what is being solved for. This is only necessary if the matrix is + * complex and \a spSEPARATED_COMPLEX_VECTORS is true. + * \param iSolution * iSolution is the imaginary portion of the vector being multiplied - * by the matrix. + * by the matrix. This is only necessary if the matrix is + * complex and \a spSEPARATED_COMPLEX_VECTORS is true. */ void -spMultiply(MatrixPtr Matrix, RealVector RHS, RealVector Solution, - RealVector iRHS, RealVector iSolution) +spMultiply( + spMatrix eMatrix, + spREAL RHS[], + spREAL Solution[] +#if spCOMPLEX AND spSEPARATED_COMPLEX_VECTORS + , spREAL iRHS[] + , spREAL iSolution[] +#endif +) { - ElementPtr pElement; - RealVector Vector; - RealNumber Sum; - int I, *pExtOrder; +register ElementPtr pElement; +register RealVector Vector; +register RealNumber Sum; +register int I, *pExtOrder; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +extern void ComplexMatrixMultiply(); - /* Begin `spMultiply'. */ - assert( IS_SPARSE( Matrix ) && !Matrix->Factored ); - if (!Matrix->RowsLinked) +/* Begin `spMultiply'. */ + ASSERT_IS_SPARSE( Matrix ); + ASSERT_IS_NOT_FACTORED( Matrix ); + if (NOT Matrix->RowsLinked) spcLinkRows(Matrix); - if (!Matrix->InternalVectorsAllocated) + if (NOT Matrix->InternalVectorsAllocated) spcCreateInternalVectors( Matrix ); +#if spCOMPLEX if (Matrix->Complex) - { - ComplexMatrixMultiply( Matrix, RHS, Solution , iRHS, iSolution ); + { ComplexMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS ); return; } +#endif - /* Initialize Intermediate vector with reordered Solution vector. */ +#if REAL +#if NOT ARRAY_OFFSET +/* Correct array pointers for ARRAY_OFFSET. */ + --RHS; + --Solution; +#endif + +/* Initialize Intermediate vector with reordered Solution vector. */ Vector = Matrix->Intermediate; pExtOrder = &Matrix->IntToExtColMap[Matrix->Size]; for (I = Matrix->Size; I > 0; I--) @@ -598,18 +643,17 @@ spMultiply(MatrixPtr Matrix, RealVector RHS, RealVector Solution, pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size]; for (I = Matrix->Size; I > 0; I--) - { - pElement = Matrix->FirstInRow[I]; + { pElement = Matrix->FirstInRow[I]; Sum = 0.0; while (pElement != NULL) - { - Sum += pElement->Real * Vector[pElement->Col]; + { Sum += pElement->Real * Vector[pElement->Col]; pElement = pElement->NextInRow; } RHS[*pExtOrder--] = Sum; } return; +#endif /* REAL */ } #endif /* MULTIPLICATION */ @@ -619,7 +663,7 @@ spMultiply(MatrixPtr Matrix, RealVector RHS, RealVector Solution, -#if MULTIPLICATION +#if spCOMPLEX AND MULTIPLICATION /* * COMPLEX MATRIX MULTIPLICATION * @@ -632,55 +676,85 @@ spMultiply(MatrixPtr Matrix, RealVector RHS, RealVector Solution, * Pointer to the matrix. * RHS (RealVector) * RHS is the right hand side. This is what is being solved for. + * This is only the real portion of the right-hand side if the matrix + * is complex and spSEPARATED_COMPLEX_VECTORS is set true. * Solution (RealVector) - * Solution is the vector being multiplied by the matrix. + * Solution is the vector being multiplied by the matrix. This is only + * the real portion if the matrix is complex and + * spSEPARATED_COMPLEX_VECTORS is set true. * iRHS (RealVector) * iRHS is the imaginary portion of the right hand side. This is - * what is being solved for. + * what is being solved for. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is true. * iSolution (RealVector) * iSolution is the imaginary portion of the vector being multiplied - * by the matrix. + * by the matrix. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is true. */ static void -ComplexMatrixMultiply( MatrixPtr Matrix, RealVector RHS, RealVector Solution , RealVector iRHS, RealVector iSolution ) +ComplexMatrixMultiply( + MatrixPtr Matrix, + RealVector RHS, + RealVector Solution +#if spSEPARATED_COMPLEX_VECTORS + , RealVector iRHS + , RealVector iSolution +#endif +) { - ElementPtr pElement; - ComplexVector Vector; - ComplexNumber Sum; - int I, *pExtOrder; +register ElementPtr pElement; +register ComplexVector Vector; +ComplexNumber Sum; +register int I, *pExtOrder; - /* Begin `ComplexMatrixMultiply'. */ +/* Begin `ComplexMatrixMultiply'. */ - /* Initialize Intermediate vector with reordered Solution vector. */ +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS + --RHS; --iRHS; + --Solution; --iSolution; +#else + RHS -= 2; Solution -= 2; +#endif +#endif + +/* Initialize Intermediate vector with reordered Solution vector. */ Vector = (ComplexVector)Matrix->Intermediate; pExtOrder = &Matrix->IntToExtColMap[Matrix->Size]; +#if spSEPARATED_COMPLEX_VECTORS for (I = Matrix->Size; I > 0; I--) - { - Vector[I].Real = Solution[*pExtOrder]; + { Vector[I].Real = Solution[*pExtOrder]; Vector[I].Imag = iSolution[*(pExtOrder--)]; } +#else + for (I = Matrix->Size; I > 0; I--) + Vector[I] = ((ComplexVector)Solution)[*(pExtOrder--)]; +#endif pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size]; for (I = Matrix->Size; I > 0; I--) - { - pElement = Matrix->FirstInRow[I]; + { pElement = Matrix->FirstInRow[I]; Sum.Real = Sum.Imag = 0.0; while (pElement != NULL) - { - /* Cmplx expression : Sum += Element * Vector[Col] */ + { /* Cmplx expression : Sum += Element * Vector[Col] */ CMPLX_MULT_ADD_ASSIGN( Sum, *pElement, Vector[pElement->Col] ); pElement = pElement->NextInRow; } +#if spSEPARATED_COMPLEX_VECTORS RHS[*pExtOrder] = Sum.Real; iRHS[*pExtOrder--] = Sum.Imag; +#else + ((ComplexVector)RHS)[*pExtOrder--] = Sum; +#endif } return; } -#endif /* MULTIPLICATION */ +#endif /* spCOMPLEX AND MULTIPLICATION */ @@ -689,51 +763,68 @@ ComplexMatrixMultiply( MatrixPtr Matrix, RealVector RHS, RealVector Solution , R -#if MULTIPLICATION && TRANSPOSE -/* - * TRANSPOSED MATRIX MULTIPLICATION - * +#if MULTIPLICATION AND TRANSPOSE +/*! * Multiplies transposed matrix by solution vector to find source vector. * Assumes matrix has not been factored. This routine can be used * as a test to see if solutions are correct. It should not be used * before spMNA_Preorder(). * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to the matrix. - * RHS (RealVector) + * \param RHS * RHS is the right hand side. This is what is being solved for. - * Solution (RealVector) + * \param Solution * Solution is the vector being multiplied by the matrix. - * iRHS (RealVector) + * \param iRHS * iRHS is the imaginary portion of the right hand side. This is - * what is being solved for. - * iSolution (RealVector) + * what is being solved for. This is only necessary if the matrix is + * complex and \a spSEPARATED_COMPLEX_VECTORS is true. + * \param iSolution * iSolution is the imaginary portion of the vector being multiplied - * by the matrix. + * by the matrix. This is only necessary if the matrix is + * complex and \a spSEPARATED_COMPLEX_VECTORS is true. */ void -spMultTransposed(MatrixPtr Matrix, RealVector RHS, RealVector Solution, - RealVector iRHS, RealVector iSolution) +spMultTransposed( + spMatrix eMatrix, + spREAL RHS[], + spREAL Solution[] +#if spCOMPLEX AND spSEPARATED_COMPLEX_VECTORS + , spREAL iRHS[] + , spREAL iSolution[] +#endif +) { - ElementPtr pElement; - RealVector Vector; - RealNumber Sum; - int I, *pExtOrder; +register ElementPtr pElement; +register RealVector Vector; +register RealNumber Sum; +register int I, *pExtOrder; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +extern void ComplexTransposedMatrixMultiply(); - /* Begin `spMultTransposed'. */ - assert( IS_SPARSE( Matrix ) && !Matrix->Factored ); - if (!Matrix->InternalVectorsAllocated) +/* Begin `spMultTransposed'. */ + ASSERT_IS_SPARSE( Matrix ); + ASSERT_IS_NOT_FACTORED( Matrix ); + if (NOT Matrix->InternalVectorsAllocated) spcCreateInternalVectors( Matrix ); +#if spCOMPLEX if (Matrix->Complex) - { - ComplexTransposedMatrixMultiply( Matrix, RHS, Solution , iRHS, iSolution ); + { ComplexTransposedMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS ); return; } +#endif - /* Initialize Intermediate vector with reordered Solution vector. */ +#if REAL +#if NOT ARRAY_OFFSET +/* Correct array pointers for ARRAY_OFFSET. */ + --RHS; + --Solution; +#endif + +/* Initialize Intermediate vector with reordered Solution vector. */ Vector = Matrix->Intermediate; pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size]; for (I = Matrix->Size; I > 0; I--) @@ -741,20 +832,19 @@ spMultTransposed(MatrixPtr Matrix, RealVector RHS, RealVector Solution, pExtOrder = &Matrix->IntToExtColMap[Matrix->Size]; for (I = Matrix->Size; I > 0; I--) - { - pElement = Matrix->FirstInCol[I]; + { pElement = Matrix->FirstInCol[I]; Sum = 0.0; while (pElement != NULL) - { - Sum += pElement->Real * Vector[pElement->Row]; + { Sum += pElement->Real * Vector[pElement->Row]; pElement = pElement->NextInCol; } RHS[*pExtOrder--] = Sum; } return; +#endif /* REAL */ } -#endif /* MULTIPLICATION && TRANSPOSE */ +#endif /* MULTIPLICATION AND TRANSPOSE */ @@ -762,7 +852,7 @@ spMultTransposed(MatrixPtr Matrix, RealVector RHS, RealVector Solution, -#if MULTIPLICATION && TRANSPOSE +#if spCOMPLEX AND MULTIPLICATION AND TRANSPOSE /* * COMPLEX TRANSPOSED MATRIX MULTIPLICATION * @@ -775,55 +865,91 @@ spMultTransposed(MatrixPtr Matrix, RealVector RHS, RealVector Solution, * Pointer to the matrix. * RHS (RealVector) * RHS is the right hand side. This is what is being solved for. + * This is only the real portion of the right-hand side if the matrix + * is complex and spSEPARATED_COMPLEX_VECTORS is set true. * Solution (RealVector) - * Solution is the vector being multiplied by the matrix. + * Solution is the vector being multiplied by the matrix. This is only + * the real portion if the matrix is complex and + * spSEPARATED_COMPLEX_VECTORS is set true. * iRHS (RealVector) * iRHS is the imaginary portion of the right hand side. This is - * what is being solved for. + * what is being solved for. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is true. * iSolution (RealVector) * iSolution is the imaginary portion of the vector being multiplied - * by the matrix. + * by the matrix. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is true. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. */ static void -ComplexTransposedMatrixMultiply( MatrixPtr Matrix, RealVector RHS, RealVector Solution , RealVector iRHS, RealVector iSolution ) +ComplexTransposedMatrixMultiply( + MatrixPtr Matrix, + RealVector RHS, + RealVector Solution +#if spSEPARATED_COMPLEX_VECTORS + , RealVector iRHS + , RealVector iSolution +#endif +) { - ElementPtr pElement; - ComplexVector Vector; - ComplexNumber Sum; - int I, *pExtOrder; +register ElementPtr pElement; +register ComplexVector Vector; +ComplexNumber Sum; +register int I, *pExtOrder; - /* Begin `ComplexMatrixMultiply'. */ +/* Begin `ComplexTransposedMatrixMultiply'. */ - /* Initialize Intermediate vector with reordered Solution vector. */ +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS + --RHS; --iRHS; + --Solution; --iSolution; +#else + RHS -= 2; Solution -= 2; +#endif +#endif + +/* Initialize Intermediate vector with reordered Solution vector. */ Vector = (ComplexVector)Matrix->Intermediate; pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size]; +#if spSEPARATED_COMPLEX_VECTORS for (I = Matrix->Size; I > 0; I--) - { - Vector[I].Real = Solution[*pExtOrder]; + { Vector[I].Real = Solution[*pExtOrder]; Vector[I].Imag = iSolution[*(pExtOrder--)]; } +#else + for (I = Matrix->Size; I > 0; I--) + Vector[I] = ((ComplexVector)Solution)[*(pExtOrder--)]; +#endif pExtOrder = &Matrix->IntToExtColMap[Matrix->Size]; for (I = Matrix->Size; I > 0; I--) - { - pElement = Matrix->FirstInCol[I]; + { pElement = Matrix->FirstInCol[I]; Sum.Real = Sum.Imag = 0.0; while (pElement != NULL) - { - /* Cmplx expression : Sum += Element * Vector[Row] */ + { /* Cmplx expression : Sum += Element * Vector[Row] */ CMPLX_MULT_ADD_ASSIGN( Sum, *pElement, Vector[pElement->Row] ); pElement = pElement->NextInCol; } +#if spSEPARATED_COMPLEX_VECTORS RHS[*pExtOrder] = Sum.Real; iRHS[*pExtOrder--] = Sum.Imag; +#else + ((ComplexVector)RHS)[*pExtOrder--] = Sum; +#endif } return; } -#endif /* MULTIPLICATION && TRANSPOSE */ +#endif /* spCOMPLEX AND MULTIPLICATION AND TRANSPOSE */ @@ -833,9 +959,7 @@ ComplexTransposedMatrixMultiply( MatrixPtr Matrix, RealVector RHS, RealVector So #if DETERMINANT -/* - * CALCULATE DETERMINANT - * +/*! * This routine in capable of calculating the determinant of the * matrix once the LU factorization has been performed. Hence, only * use this routine after spFactor() and before spClear(). @@ -849,78 +973,83 @@ ComplexTransposedMatrixMultiply( MatrixPtr Matrix, RealVector RHS, RealVector So * point number. For this reason the determinant is scaled to a * reasonable value and the logarithm of the scale factor is returned. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * A pointer to the matrix for which the determinant is desired. - * pExponent (int *) + * \param pExponent * The logarithm base 10 of the scale factor for the determinant. To find * the actual determinant, Exponent should be added to the exponent of * Determinant. - * pDeterminant (RealNumber *) + * \param pDeterminant * The real portion of the determinant. This number is scaled to be * greater than or equal to 1.0 and less than 10.0. - * piDeterminant (RealNumber *) + * \param piDeterminant * The imaginary portion of the determinant. When the matrix is real * this pointer need not be supplied, nothing will be returned. This * number is scaled to be greater than or equal to 1.0 and less than 10.0. - * - * >>> Local variables: + */ +/* >>> Local variables: * Norm (RealNumber) * L-infinity norm of a complex number. * Size (int) - * Local storage for Matrix->Size. Placed in a for speed. + * Local storage for Matrix->Size. Placed in a register for speed. * Temp (RealNumber) * Temporary storage for real portion of determinant. */ void -spDeterminant(MatrixPtr Matrix, int *pExponent, RealNumber *pDeterminant, - RealNumber *piDeterminant) +spDeterminant( + spMatrix eMatrix, + int *pExponent, + spREAL *pDeterminant +#if spCOMPLEX + , spREAL *piDeterminant +#endif +) { - int I, Size; - RealNumber Norm, nr, ni; - ComplexNumber Pivot, cDeterminant; +register MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I, Size; +RealNumber Norm, nr, ni; +ComplexNumber Pivot, cDeterminant; #define NORM(a) (nr = ABS((a).Real), ni = ABS((a).Imag), MAX (nr,ni)) - /* Begin `spDeterminant'. */ - assert( IS_SPARSE( Matrix ) && IS_FACTORED(Matrix) ); +/* Begin `spDeterminant'. */ + ASSERT_IS_SPARSE( Matrix ); + ASSERT_NO_ERRORS( Matrix ); + ASSERT_IS_FACTORED( Matrix ); *pExponent = 0; if (Matrix->Error == spSINGULAR) - { - *pDeterminant = 0.0; + { *pDeterminant = 0.0; +#if spCOMPLEX if (Matrix->Complex) *piDeterminant = 0.0; +#endif return; } Size = Matrix->Size; I = 0; +#if spCOMPLEX if (Matrix->Complex) /* Complex Case. */ - { - cDeterminant.Real = 1.0; + { cDeterminant.Real = 1.0; cDeterminant.Imag = 0.0; while (++I <= Size) - { - CMPLX_RECIPROCAL( Pivot, *Matrix->Diag[I] ); + { CMPLX_RECIPROCAL( Pivot, *Matrix->Diag[I] ); CMPLX_MULT_ASSIGN( cDeterminant, Pivot ); - /* Scale Determinant. */ +/* Scale Determinant. */ Norm = NORM( cDeterminant ); if (Norm != 0.0) - { - while (Norm >= 1.0e12) - { - cDeterminant.Real *= 1.0e-12; + { while (Norm >= 1.0e12) + { cDeterminant.Real *= 1.0e-12; cDeterminant.Imag *= 1.0e-12; *pExponent += 12; Norm = NORM( cDeterminant ); } while (Norm < 1.0e-12) - { - cDeterminant.Real *= 1.0e12; + { cDeterminant.Real *= 1.0e12; cDeterminant.Imag *= 1.0e12; *pExponent -= 12; Norm = NORM( cDeterminant ); @@ -928,20 +1057,17 @@ spDeterminant(MatrixPtr Matrix, int *pExponent, RealNumber *pDeterminant, } } - /* Scale Determinant again, this time to be between 1.0 <= x < 10.0. */ +/* Scale Determinant again, this time to be between 1.0 <= x < 10.0. */ Norm = NORM( cDeterminant ); if (Norm != 0.0) - { - while (Norm >= 10.0) - { - cDeterminant.Real *= 0.1; + { while (Norm >= 10.0) + { cDeterminant.Real *= 0.1; cDeterminant.Imag *= 0.1; (*pExponent)++; Norm = NORM( cDeterminant ); } while (Norm < 1.0) - { - cDeterminant.Real *= 10.0; + { cDeterminant.Real *= 10.0; cDeterminant.Imag *= 10.0; (*pExponent)--; Norm = NORM( cDeterminant ); @@ -953,49 +1079,45 @@ spDeterminant(MatrixPtr Matrix, int *pExponent, RealNumber *pDeterminant, *pDeterminant = cDeterminant.Real; *piDeterminant = cDeterminant.Imag; } +#endif /* spCOMPLEX */ +#if REAL AND spCOMPLEX else - { - /* Real Case. */ +#endif +#if REAL + { /* Real Case. */ *pDeterminant = 1.0; while (++I <= Size) - { - *pDeterminant /= Matrix->Diag[I]->Real; + { *pDeterminant /= Matrix->Diag[I]->Real; - /* Scale Determinant. */ +/* Scale Determinant. */ if (*pDeterminant != 0.0) - { - while (ABS(*pDeterminant) >= 1.0e12) - { - *pDeterminant *= 1.0e-12; + { while (ABS(*pDeterminant) >= 1.0e12) + { *pDeterminant *= 1.0e-12; *pExponent += 12; } while (ABS(*pDeterminant) < 1.0e-12) - { - *pDeterminant *= 1.0e12; + { *pDeterminant *= 1.0e12; *pExponent -= 12; } } } - /* Scale Determinant again, this time to be between 1.0 <= x < - 10.0. */ +/* Scale Determinant again, this time to be between 1.0 <= x < 10.0. */ if (*pDeterminant != 0.0) - { - while (ABS(*pDeterminant) >= 10.0) - { - *pDeterminant *= 0.1; + { while (ABS(*pDeterminant) >= 10.0) + { *pDeterminant *= 0.1; (*pExponent)++; } while (ABS(*pDeterminant) < 1.0) - { - *pDeterminant *= 10.0; + { *pDeterminant *= 10.0; (*pExponent)--; } } if (Matrix->NumberOfInterchangesIsOdd) *pDeterminant = -*pDeterminant; } +#endif /* REAL */ } #endif /* DETERMINANT */ @@ -1006,18 +1128,15 @@ spDeterminant(MatrixPtr Matrix, int *pExponent, RealNumber *pDeterminant, - #if STRIP -/* - * STRIP FILL-INS FROM MATRIX - * + +/*! * Strips the matrix of all fill-ins. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to the matrix to be stripped. - * - * >>> Local variables: + */ +/* >>> Local variables: * pElement (ElementPtr) * Pointer that is used to step through the matrix. * ppElement (ElementPtr *) @@ -1032,28 +1151,27 @@ spDeterminant(MatrixPtr Matrix, int *pExponent, RealNumber *pDeterminant, */ void -spStripFills(MatrixPtr Matrix) +spStripFills( spMatrix eMatrix ) { - struct FillinListNodeStruct *pListNode; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +struct FillinListNodeStruct *pListNode; - /* Begin `spStripFills'. */ - assert( IS_SPARSE( Matrix ) ); +/* Begin `spStripFills'. */ + ASSERT_IS_SPARSE( Matrix ); if (Matrix->Fillins == 0) return; Matrix->NeedsOrdering = YES; Matrix->Elements -= Matrix->Fillins; Matrix->Fillins = 0; - /* Mark the fill-ins. */ - { - ElementPtr pFillin, pLastFillin; +/* Mark the fill-ins. */ + { register ElementPtr pFillin, pLastFillin; pListNode = Matrix->LastFillinListNode = Matrix->FirstFillinListNode; Matrix->FillinsRemaining = pListNode->NumberOfFillinsInList; Matrix->NextAvailFillin = pListNode->pFillinList; while (pListNode != NULL) - { - pFillin = pListNode->pFillinList; + { pFillin = pListNode->pFillinList; pLastFillin = &(pFillin[ pListNode->NumberOfFillinsInList - 1 ]); while (pFillin <= pLastFillin) (pFillin++)->Row = 0; @@ -1061,20 +1179,16 @@ spStripFills(MatrixPtr Matrix) } } - /* Unlink fill-ins by searching for elements marked with Row = 0. */ - { - ElementPtr pElement, *ppElement; - int I, Size = Matrix->Size; +/* Unlink fill-ins by searching for elements marked with Row = 0. */ + { register ElementPtr pElement, *ppElement; + register int I, Size = Matrix->Size; - /* Unlink fill-ins in all columns. */ +/* Unlink fill-ins in all columns. */ for (I = 1; I <= Size; I++) - { - ppElement = &(Matrix->FirstInCol[I]); + { ppElement = &(Matrix->FirstInCol[I]); while ((pElement = *ppElement) != NULL) - { - if (pElement->Row == 0) - { - *ppElement = pElement->NextInCol; /* Unlink fill-in. */ + { if (pElement->Row == 0) + { *ppElement = pElement->NextInCol; /* Unlink fill-in. */ if (Matrix->Diag[pElement->Col] == pElement) Matrix->Diag[pElement->Col] = NULL; } @@ -1083,13 +1197,11 @@ spStripFills(MatrixPtr Matrix) } } - /* Unlink fill-ins in all rows. */ +/* Unlink fill-ins in all rows. */ for (I = 1; I <= Size; I++) - { - ppElement = &(Matrix->FirstInRow[I]); + { ppElement = &(Matrix->FirstInRow[I]); while ((pElement = *ppElement) != NULL) - { - if (pElement->Row == 0) + { if (pElement->Row == 0) *ppElement = pElement->NextInRow; /* Unlink fill-in. */ else ppElement = &pElement->NextInRow; /* Skip element. */ @@ -1098,51 +1210,6 @@ spStripFills(MatrixPtr Matrix) } return; } - -/* Same as above, but strips entire matrix without destroying the - * frame. This assumes that the matrix will be replaced with one of - * the same size. */ -void -spStripMatrix(MatrixPtr Matrix) -{ - /* Begin `spStripMatrix'. */ - assert( IS_SPARSE( Matrix ) ); - if (Matrix->Elements == 0) return; - Matrix->RowsLinked = NO; - Matrix->NeedsOrdering = YES; - Matrix->Elements = 0; - Matrix->Originals = 0; - Matrix->Fillins = 0; - - /* Reset the element lists. */ - { - struct ElementListNodeStruct *pListNode; - - pListNode = Matrix->LastElementListNode = Matrix->FirstElementListNode; - Matrix->ElementsRemaining = pListNode->NumberOfElementsInList; - Matrix->NextAvailElement = pListNode->pElementList; - } - - /* Reset the fill-in lists. */ - { - struct FillinListNodeStruct *pListNode; - - pListNode = Matrix->LastFillinListNode = Matrix->FirstFillinListNode; - Matrix->FillinsRemaining = pListNode->NumberOfFillinsInList; - Matrix->NextAvailFillin = pListNode->pFillinList; - } - - /* Reset the Row, Column and Diag pointers */ - { - int I, Size = Matrix->Size; - for (I = 1; I <= Size; I++) - { - Matrix->FirstInRow[I] = NULL; - Matrix->FirstInCol[I] = NULL; - Matrix->Diag[I] = NULL; - } - } -} #endif @@ -1151,24 +1218,21 @@ spStripMatrix(MatrixPtr Matrix) -#if TRANSLATE && DELETE -/* - * DELETE A ROW AND COLUMN FROM THE MATRIX - * +#if TRANSLATE AND DELETE +/*! * Deletes a row and a column from a matrix. * * Sparse will abort if an attempt is made to delete a row or column that * doesn't exist. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to the matrix in which the row and column are to be deleted. - * Row (int) + * \param Row * Row to be deleted. - * Col (int) + * \param Col * Column to be deleted. - * - * >>> Local variables: + */ +/* >>> Local variables: * ExtCol (int) * The external column that is being deleted. * ExtRow (int) @@ -1187,52 +1251,54 @@ spStripMatrix(MatrixPtr Matrix) */ void -spDeleteRowAndCol(MatrixPtr Matrix, int Row, int Col) +spDeleteRowAndCol( + spMatrix eMatrix, + int Row, + int Col +) { - ElementPtr pElement, *ppElement, pLastElement; - int Size, ExtRow, ExtCol; - ElementPtr spcFindElementInCol(); +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement, *ppElement, pLastElement; +int Size, ExtRow, ExtCol; - /* Begin `spDeleteRowAndCol'. */ - - assert( IS_SPARSE(Matrix) && Row > 0 && Col > 0 ); - assert( Row <= Matrix->ExtSize && Col <= Matrix->ExtSize ); +/* Begin `spDeleteRowAndCol'. */ + ASSERT_IS_SPARSE( Matrix ); + vASSERT( (Row > 0) AND (Col > 0), "Nonpositive row or column number" ); + vASSERT( (Row <= Matrix->ExtSize) AND (Col <= Matrix->ExtSize), + "Row or column number too large" ); Size = Matrix->Size; ExtRow = Row; ExtCol = Col; - if (!Matrix->RowsLinked) - spcLinkRows( Matrix ); + if (NOT Matrix->RowsLinked) spcLinkRows( Matrix ); Row = Matrix->ExtToIntRowMap[Row]; Col = Matrix->ExtToIntColMap[Col]; - assert( Row > 0 && Col > 0 ); + ASSERT( Row > 0 AND Col > 0 ); - /* Move Row so that it is the last row in the matrix. */ +/* Move Row so that it is the last row in the matrix. */ if (Row != Size) spcRowExchange( Matrix, Row, Size ); - /* Move Col so that it is the last column in the matrix. */ +/* Move Col so that it is the last column in the matrix. */ if (Col != Size) spcColExchange( Matrix, Col, Size ); - /* Correct Diag pointers. */ +/* Correct Diag pointers. */ if (Row == Col) - SWAP( ElementPtr, Matrix->Diag[Row], Matrix->Diag[Size] ); - else { - Matrix->Diag[Row] = spcFindElementInCol(Matrix, - Matrix->FirstInCol+Row, - Row, Row, NO ); - Matrix->Diag[Col] = spcFindElementInCol(Matrix, - Matrix->FirstInCol+Col, - Col, Col, NO ); + SWAP( ElementPtr, Matrix->Diag[Row], Matrix->Diag[Size] ) + else + { Matrix->Diag[Row] = spcFindDiag( Matrix, Row ); + Matrix->Diag[Col] = spcFindDiag( Matrix, Col ); } - /* Delete last row and column of the matrix. */ - /* Break the column links to every element in the last row. */ +/* + * Delete last row and column of the matrix. + */ +/* Break the column links to every element in the last row. */ pLastElement = Matrix->FirstInRow[ Size ]; - while (pLastElement != NULL) { - ppElement = &(Matrix->FirstInCol[ pLastElement->Col ]); - while ((pElement = *ppElement) != NULL) { - if (pElement == pLastElement) + while (pLastElement != NULL) + { ppElement = &(Matrix->FirstInCol[ pLastElement->Col ]); + while ((pElement = *ppElement) != NULL) + { if (pElement == pLastElement) *ppElement = NULL; /* Unlink last element in column. */ else ppElement = &pElement->NextInCol; /* Skip element. */ @@ -1240,20 +1306,20 @@ spDeleteRowAndCol(MatrixPtr Matrix, int Row, int Col) pLastElement = pLastElement->NextInRow; } - /* Break the row links to every element in the last column. */ +/* Break the row links to every element in the last column. */ pLastElement = Matrix->FirstInCol[ Size ]; - while (pLastElement != NULL) { - ppElement = &(Matrix->FirstInRow[ pLastElement->Row ]); - while ((pElement = *ppElement) != NULL) { - if (pElement == pLastElement) - *ppElement = NULL; /* Unlink last element in row. */ + while (pLastElement != NULL) + { ppElement = &(Matrix->FirstInRow[ pLastElement->Row ]); + while ((pElement = *ppElement) != NULL) + { if (pElement == pLastElement) + *ppElement = NULL; /* Unlink last element in row. */ else - ppElement = &pElement->NextInRow; /* Skip element. */ + ppElement = &pElement->NextInRow; /* Skip element. */ } pLastElement = pLastElement->NextInCol; } - /* Clean up some details. */ +/* Clean up some details. */ Matrix->Size = Size - 1; Matrix->Diag[Size] = NULL; Matrix->FirstInRow[Size] = NULL; @@ -1275,53 +1341,52 @@ spDeleteRowAndCol(MatrixPtr Matrix, int Row, int Col) #if PSEUDOCONDITION -/* - * CALCULATE PSEUDOCONDITION - * +/*! * Computes the magnitude of the ratio of the largest to the smallest * pivots. This quantity is an indicator of ill-conditioning in the * matrix. If this ratio is large, and if the matrix is scaled such * that uncertainties in the RHS and the matrix entries are - * equilibrated, then the matrix is ill-conditioned. However, a - * small ratio does not necessarily imply that the matrix is - * well-conditioned. This routine must only be used after a matrix - * has been factored by spOrderAndFactor() or spFactor() and before - * it is cleared by spClear() or spInitialize(). The pseudocondition - * is faster to compute than the condition number calculated by + * equilibrated, then the matrix is ill-conditioned. However, a small + * ratio does not necessarily imply that the matrix is + * well-conditioned. This routine must only be used after a matrix has + * been factored by spOrderAndFactor() or spFactor() and before it is + * cleared by spClear() or spInitialize(). The pseudocondition is + * faster to compute than the condition number calculated by * spCondition(), but is not as informative. * - * >>> Returns: + * \return * The magnitude of the ratio of the largest to smallest pivot used during * previous factorization. If the matrix was singular, zero is returned. * - * >>> Arguments: - * Matrix (char *) - * Pointer to the matrix. */ + * \param eMatrix + * Pointer to the matrix. + */ -RealNumber -spPseudoCondition(MatrixPtr Matrix) +spREAL +spPseudoCondition( spMatrix eMatrix ) { - int I; - ArrayOfElementPtrs Diag; + MatrixPtr Matrix = (MatrixPtr)eMatrix; + register int I; + register ArrayOfElementPtrs Diag; RealNumber MaxPivot, MinPivot, Mag; /* Begin `spPseudoCondition'. */ - - assert( IS_SPARSE(Matrix) && IS_FACTORED(Matrix) ); - if (Matrix->Error == spSINGULAR || Matrix->Error == spZERO_DIAG) - return 0.0; + ASSERT_IS_SPARSE( Matrix ); + ASSERT_NO_ERRORS( Matrix ); + ASSERT_IS_FACTORED( Matrix ); + if (Matrix->Error == spSINGULAR OR Matrix->Error == spZERO_DIAG) + return 0.0; Diag = Matrix->Diag; MaxPivot = MinPivot = ELEMENT_MAG( Diag[1] ); for (I = 2; I <= Matrix->Size; I++) - { - Mag = ELEMENT_MAG( Diag[I] ); + { Mag = ELEMENT_MAG( Diag[I] ); if (Mag > MaxPivot) MaxPivot = Mag; else if (Mag < MinPivot) MinPivot = Mag; } - assert( MaxPivot > 0.0); + ASSERT( MaxPivot > 0.0 ); return MaxPivot / MinPivot; } #endif @@ -1334,28 +1399,25 @@ spPseudoCondition(MatrixPtr Matrix) #if CONDITION -/* - * ESTIMATE CONDITION NUMBER - * +/*! * Computes an estimate of the condition number using a variation on - * the LINPACK condition number estimation algorithm. This quantity - * is an indicator of ill-conditioning in the matrix. To avoid - * problems with overflow, the reciprocal of the condition number is - * returned. If this number is small, and if the matrix is scaled - * such that uncertainties in the RHS and the matrix entries are - * equilibrated, then the matrix is ill-conditioned. If the this - * number is near one, the matrix is well conditioned. This routine - * must only be used after a matrix has been factored by - * spOrderAndFactor() or spFactor() and before it is cleared by - * spClear() or spInitialize(). + * the LINPACK condition number estimation algorithm. This quantity is + * an indicator of ill-conditioning in the matrix. To avoid problems + * with overflow, the reciprocal of the condition number is returned. + * If this number is small, and if the matrix is scaled such that + * uncertainties in the RHS and the matrix entries are equilibrated, + * then the matrix is ill-conditioned. If the this number is near + * one, the matrix is well conditioned. This routine must only be + * used after a matrix has been factored by spOrderAndFactor() or + * spFactor() and before it is cleared by spClear() or spInitialize(). * * Unlike the LINPACK condition number estimator, this routines * returns the L infinity condition number. This is an artifact of * Sparse placing ones on the diagonal of the upper triangular matrix - * rather than the lower. This difference should be of no - * importance. + * rather than the lower. This difference should be of no importance. + * + * \b References: * - * References: * A.K. Cline, C.B. Moler, G.W. Stewart, J.H. Wilkinson. An estimate * for the condition number of a matrix. SIAM Journal on Numerical * Analysis. Vol. 16, No. 2, pages 368-375, April 1979. @@ -1371,72 +1433,82 @@ spPseudoCondition(MatrixPtr Matrix) * Journal on Scientific and Statistical Computing. Vol. 1, No. 2, * pages 205-209, June 1980. * - * >>> Returns: + * \return * The reciprocal of the condition number. If the matrix was singular, * zero is returned. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to the matrix. - * NormOfMatrix (RealNumber) + * \param NormOfMatrix * The L-infinity norm of the unfactored matrix as computed by * spNorm(). - * pError (int *) - * Used to return error code. - * - * >>> Possible errors: - * spSINGULAR - * spNO_MEMORY */ + * \param pError + * Used to return error code. Possible errors include \a spSINGULAR + * or \a spNO_MEMORY. + */ -RealNumber -spCondition(MatrixPtr Matrix, RealNumber NormOfMatrix, int *pError) +spREAL +spCondition( + spMatrix eMatrix, + spREAL NormOfMatrix, + int *pError +) { - ElementPtr pElement; - RealVector T, Tm; - int I, K, Row; - ElementPtr pPivot; - int Size; - RealNumber E, Em, Wp, Wm, ASp, ASm, ASw, ASy, ASv, ASz, MaxY, ScaleFactor; - RealNumber Linpack, OLeary, InvNormOfInverse, ComplexCondition(); +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register RealVector T, Tm; +register int I, K, Row; +ElementPtr pPivot; +int Size; +RealNumber E, Em, Wp, Wm, ASp, ASm, ASw, ASy, ASv, ASz, MaxY, ScaleFactor; +RealNumber Linpack, OLeary, InvNormOfInverse, ComplexCondition(); #define SLACK 1e4 - /* Begin `spCondition'. */ - - assert( IS_SPARSE(Matrix) && IS_FACTORED(Matrix) ); +/* Begin `spCondition'. */ + ASSERT_IS_SPARSE( Matrix ); + ASSERT_NO_ERRORS( Matrix ); + ASSERT_IS_FACTORED( Matrix ); *pError = Matrix->Error; if (Matrix->Error >= spFATAL) return 0.0; if (NormOfMatrix == 0.0) - { - *pError = spSINGULAR; + { *pError = spSINGULAR; return 0.0; } +#if spCOMPLEX if (Matrix->Complex) return ComplexCondition( Matrix, NormOfMatrix, pError ); +#endif +#if REAL Size = Matrix->Size; T = Matrix->Intermediate; +#if spCOMPLEX Tm = Matrix->Intermediate + Size; +#else + Tm = ALLOC( RealNumber, Size+1 ); + if (Tm == NULL) + { *pError = spNO_MEMORY; + return 0.0; + } +#endif for (I = Size; I > 0; I--) T[I] = 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. */ +/* + * 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. */ +/* Forward elimination. Solves Lw = e while choosing e. */ E = 1.0; for (I = 1; I <= Size; I++) - { - pPivot = Matrix->Diag[I]; + { pPivot = Matrix->Diag[I]; if (T[I] < 0.0) Em = -E; else Em = E; Wm = (Em + T[I]) * pPivot->Real; if (ABS(Wm) > SLACK) - { - ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(Wm) ); + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(Wm) ); for (K = Size; K > 0; K--) T[K] *= ScaleFactor; E *= ScaleFactor; Em *= ScaleFactor; @@ -1446,12 +1518,10 @@ spCondition(MatrixPtr Matrix, RealNumber NormOfMatrix, int *pError) ASp = ABS(T[I] - Em); ASm = ABS(Em + T[I]); - /* Update T for both values of W, minus value is placed in - Tm. */ +/* Update T for both values of W, minus value is placed in Tm. */ pElement = pPivot->NextInCol; while (pElement != NULL) - { - Row = pElement->Row; + { Row = pElement->Row; Tm[Row] = T[Row] - (Wm * pElement->Real); T[Row] -= (Wp * pElement->Real); ASp += ABS(T[Row]); @@ -1459,127 +1529,115 @@ spCondition(MatrixPtr Matrix, RealNumber NormOfMatrix, int *pError) pElement = pElement->NextInCol; } - /* If minus value causes more growth, overwrite T with its - values. */ +/* If minus value causes more growth, overwrite T with its values. */ if (ASm > ASp) - { - T[I] = Wm; + { T[I] = Wm; pElement = pPivot->NextInCol; while (pElement != NULL) - { - T[pElement->Row] = Tm[pElement->Row]; + { 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. */ +/* 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 += ABS(T[I]); ScaleFactor = 1.0 / (SLACK * ASw); if (ScaleFactor < 0.5) - { - for (I = Size; I > 0; I--) T[I] *= ScaleFactor; + { for (I = Size; I > 0; I--) T[I] *= ScaleFactor; E *= ScaleFactor; } - /* Backward Substitution. Solves Uy = w.*/ +/* Backward Substitution. Solves Uy = w.*/ for (I = Size; I >= 1; I--) - { - pElement = Matrix->Diag[I]->NextInRow; + { pElement = Matrix->Diag[I]->NextInRow; while (pElement != NULL) - { - T[I] -= pElement->Real * T[pElement->Col]; + { T[I] -= pElement->Real * T[pElement->Col]; pElement = pElement->NextInRow; } if (ABS(T[I]) > SLACK) - { - ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) ); + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) ); for (K = Size; K > 0; K--) T[K] *= ScaleFactor; E *= ScaleFactor; } } - /* Compute 1-norm of T, which now contains y, and scale ||T|| to - 1/SLACK. */ +/* 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 += ABS(T[I]); ScaleFactor = 1.0 / (SLACK * ASy); if (ScaleFactor < 0.5) - { - for (I = Size; I > 0; I--) T[I] *= ScaleFactor; + { for (I = Size; I > 0; I--) T[I] *= ScaleFactor; ASy = 1.0 / SLACK; E *= ScaleFactor; } - /* Compute infinity-norm of T for O'Leary's estimate. */ +/* Compute infinity-norm of T for O'Leary's estimate. */ for (MaxY = 0.0, I = Size; I > 0; I--) if (MaxY < ABS(T[I])) MaxY = ABS(T[I]); - /* - * Part 2. - * - * A* z = y where the * represents the transpose. Recall that A = - * LU implies A* = U* L*. */ +/* + * Part 2. A* z = y where the * represents the transpose. + * Recall that A = LU implies A* = U* L*. + */ - /* Forward elimination, U* v = y. */ +/* Forward elimination, U* v = y. */ for (I = 1; I <= Size; I++) - { - pElement = Matrix->Diag[I]->NextInRow; + { pElement = Matrix->Diag[I]->NextInRow; while (pElement != NULL) - { - T[pElement->Col] -= T[I] * pElement->Real; + { T[pElement->Col] -= T[I] * pElement->Real; pElement = pElement->NextInRow; } if (ABS(T[I]) > SLACK) - { - ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) ); + { 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 v, and scale ||T|| to 1/SLACK. */ +/* 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 += ABS(T[I]); ScaleFactor = 1.0 / (SLACK * ASv); if (ScaleFactor < 0.5) - { - for (I = Size; I > 0; I--) T[I] *= ScaleFactor; + { for (I = Size; I > 0; I--) T[I] *= ScaleFactor; ASy *= ScaleFactor; } - /* Backward Substitution, L* z = v. */ +/* Backward Substitution, L* z = v. */ for (I = Size; I >= 1; I--) - { - pPivot = Matrix->Diag[I]; + { pPivot = Matrix->Diag[I]; pElement = pPivot->NextInCol; while (pElement != NULL) - { - T[I] -= pElement->Real * T[pElement->Row]; + { T[I] -= pElement->Real * T[pElement->Row]; pElement = pElement->NextInCol; } T[I] *= pPivot->Real; if (ABS(T[I]) > SLACK) - { - ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) ); + { 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. */ +/* 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 * @@ -1602,54 +1660,50 @@ spCondition(MatrixPtr Matrix, RealNumber NormOfMatrix, int *pError) */ static RealNumber -ComplexCondition( Matrix, NormOfMatrix, pError ) - -MatrixPtr Matrix; -RealNumber NormOfMatrix; -int *pError; +ComplexCondition( + MatrixPtr Matrix, + RealNumber NormOfMatrix, + int *pError +) { - ElementPtr pElement; - ComplexVector T, Tm; - 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; +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'. */ +/* Begin `ComplexCondition'. */ Size = Matrix->Size; T = (ComplexVector)Matrix->Intermediate; - Tm = SP_MALLOC( ComplexNumber, Size+1 ); + Tm = ALLOC( ComplexNumber, Size+1 ); if (Tm == NULL) - { - *pError = spNO_MEMORY; + { *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. */ +/* + * 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. */ +/* Forward elimination. Solves Lw = e while choosing e. */ E = 1.0; for (I = 1; I <= Size; I++) - { - pPivot = Matrix->Diag[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) ); + { 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; @@ -1661,11 +1715,10 @@ int *pError; ASp = CMPLX_1_NORM( Wp ); CMPLX_MULT_ASSIGN( Wp, *pPivot ); - /* Update T for both values of W, minus value is placed in Tm. */ +/* Update T for both values of W, minus value is placed in Tm. */ pElement = pPivot->NextInCol; while (pElement != NULL) - { - Row = pElement->Row; + { 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. */ @@ -1675,186 +1728,167 @@ int *pError; pElement = pElement->NextInCol; } - /* If minus value causes more growth, overwrite T with its - values. */ +/* If minus value causes more growth, overwrite T with its values. */ if (ASm > ASp) - { - T[I] = Wm; + { T[I] = Wm; pElement = pPivot->NextInCol; while (pElement != NULL) - { - T[pElement->Row] = Tm[pElement->Row]; + { 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. */ +/* 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 ); + { for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor ); E *= ScaleFactor; } - /* Backward Substitution. Solves Uy = w.*/ +/* Backward Substitution. Solves Uy = w.*/ for (I = Size; I >= 1; I--) - { - pElement = Matrix->Diag[I]->NextInRow; + { pElement = Matrix->Diag[I]->NextInRow; while (pElement != NULL) - { - /* Cmplx expr: T[I] -= T[pElement->Col] * *pElement. */ + { /* 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]) ); + { 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. */ +/* 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 ); + { 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. */ +/* 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*. */ +/* + * Part 2. A* z = y where the * represents the transpose. + * Recall that A = LU implies A* = U* L*. + */ - /* Forward elimination, U* v = y. */ +/* Forward elimination, U* v = y. */ for (I = 1; I <= Size; I++) - { - pElement = Matrix->Diag[I]->NextInRow; + { pElement = Matrix->Diag[I]->NextInRow; while (pElement != NULL) - { - /* Cmplx expr: T[pElement->Col] -= T[I] * *pElement. */ + { /* 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]) ); + { 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. */ +/* 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 ); + { for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor ); ASy *= ScaleFactor; } - /* Backward Substitution, L* z = v. */ +/* Backward Substitution, L* z = v. */ for (I = Size; I >= 1; I--) - { - pPivot = Matrix->Diag[I]; + { pPivot = Matrix->Diag[I]; pElement = pPivot->NextInCol; while (pElement != NULL) - { - /* Cmplx expr: T[I] -= T[pElement->Row] * *pElement. */ + { /* 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]) ); + { 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. */ +/* Compute 1-norm of T, which now contains z. */ for (ASz = 0.0, I = Size; I > 0; I--) ASz += CMPLX_1_NORM(T[I]); - SP_FREE( Tm ); + FREE( Tm ); Linpack = ASy / ASz; OLeary = E / MaxY; InvNormOfInverse = MIN( Linpack, OLeary ); return InvNormOfInverse / NormOfMatrix; } +#endif /* spCOMPLEX */ -/* - * L-INFINITY MATRIX NORM - * +/*! * Computes the L-infinity norm of an unfactored matrix. It is a fatal * error to pass this routine a factored matrix. * - * One difficulty is that the rows may not be linked. - * - * >>> Returns: + * \return * The largest absolute row sum of matrix. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to the matrix. */ -RealNumber -spNorm(MatrixPtr Matrix) +spREAL +spNorm( spMatrix eMatrix ) { - ElementPtr pElement; - int I; - RealNumber Max = 0.0, AbsRowSum; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register int I; +RealNumber Max = 0.0, AbsRowSum; - /* Begin `spNorm'. */ - assert( IS_SPARSE(Matrix) && !IS_FACTORED(Matrix) ); - if (!Matrix->RowsLinked) spcLinkRows( Matrix ); +/* 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 (!Matrix->Complex) - { - for (I = Matrix->Size; I > 0; I--) - { - pElement = Matrix->FirstInRow[I]; +/* 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 ); + { AbsRowSum += ABS( pElement->Real ); pElement = pElement->NextInRow; } if (Max < AbsRowSum) Max = AbsRowSum; } } - else - { - for (I = Matrix->Size; I > 0; I--) - { - pElement = Matrix->FirstInRow[I]; +#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 ); + { AbsRowSum += CMPLX_1_NORM( *pElement ); pElement = pElement->NextInRow; } if (Max < AbsRowSum) Max = AbsRowSum; } } +#endif return Max; } #endif /* CONDITION */ @@ -1865,28 +1899,29 @@ spNorm(MatrixPtr Matrix) #if STABILITY -/* - * STABILITY OF FACTORIZATION +/*! + * 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$. * - * The following routines 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 E = [e_ij] - * of error terms such that A+E = LU. This routine finds a bound on - * |e_ij|. Erisman & Reid [1] showed that |e_ij| < 3.01 u rho m_ij, - * where u is the machine rounding unit, rho = max a_ij where the max - * is taken over every row i, column j, and step k, and m_ij is the - * number of multiplications required in the computation of l_ij if i - * > j or u_ij otherwise. Barlow [2] showed that rho < max_i || l_i - * ||_p max_j || u_j ||_q where 1/p + 1/q = 1. - * - * The first routine finds the magnitude on the largest element in - * the matrix. If the matrix has not yet been factored, the largest + * 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 p = oo and q = 1. The ratio of these + * 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 @@ -1896,17 +1931,17 @@ spNorm(MatrixPtr Matrix) * 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 m_ij and + * 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 e_ij using the bound of Erisman and Reid. The second - * routine computes a tighter bound (with more work) based on work by - * Gear [3], |e_ij| < 1.01 u rho (t c^3 + (1 + t)c^2) where t is the - * threshold and c is the maximum number of off-diagonal elements in - * any row of L. The expensive part of computing this bound is - * determining the maximum number of off-diagonals in L, which - * changes only when the order of the matrix changes. This number is - * computed and saved, and only recomputed if the matrix is - * reordered. + * 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 @@ -1917,172 +1952,162 @@ spNorm(MatrixPtr Matrix) * 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. */ - -/* - * LARGEST ELEMENT IN MATRIX + * Matrices." Oxford 1986. pp 99. * - * >>> Returns: + * \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. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to the matrix. */ -RealNumber -spLargestElement(MatrixPtr Matrix) +spREAL +spLargestElement( spMatrix eMatrix ) { - int I; - RealNumber Mag, AbsColSum, Max = 0.0, MaxRow = 0.0, MaxCol = 0.0; - RealNumber Pivot; - ComplexNumber cPivot; - ElementPtr pElement, pDiag; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I; +RealNumber Mag, AbsColSum, Max = 0.0, MaxRow = 0.0, MaxCol = 0.0; +RealNumber Pivot; +ComplexNumber cPivot; +register ElementPtr pElement, pDiag; - /* Begin `spLargestElement'. */ - assert( IS_SPARSE(Matrix) ); +/* Begin `spLargestElement'. */ + ASSERT_IS_SPARSE( Matrix ); - if (Matrix->Factored && !Matrix->Complex) - { - if (Matrix->Error == spSINGULAR) return 0.0; +#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. */ +/* Find the bound on the size of the largest element over all factorization. */ for (I = 1; I <= Matrix->Size; I++) - { - pDiag = Matrix->Diag[I]; + { pDiag = Matrix->Diag[I]; - /* Lower triangular matrix. */ +/* 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 ); + { Mag = ABS( pElement->Real ); if (Mag > MaxRow) MaxRow = Mag; pElement = pElement->NextInRow; } - /* Upper triangular matrix. */ +/* Upper triangular matrix. */ pElement = Matrix->FirstInCol[I]; AbsColSum = 1.0; /* Diagonal of U is unity. */ while (pElement != pDiag) - { - AbsColSum += ABS( pElement->Real ); + { AbsColSum += ABS( pElement->Real ); pElement = pElement->NextInCol; } if (AbsColSum > MaxCol) MaxCol = AbsColSum; } } - else if (!Matrix->Complex) - { - for (I = 1; I <= Matrix->Size; I++) - { - pElement = Matrix->FirstInCol[I]; + else if (NOT Matrix->Complex) + { for (I = 1; I <= Matrix->Size; I++) + { pElement = Matrix->FirstInCol[I]; while (pElement != NULL) - { - Mag = ABS( pElement->Real ); + { Mag = ABS( pElement->Real ); if (Mag > Max) Max = Mag; pElement = pElement->NextInCol; } } return Max; } - if (Matrix->Factored && Matrix->Complex) - { - if (Matrix->Error == spSINGULAR) return 0.0; +#endif +#if spCOMPLEX + if (Matrix->Factored AND Matrix->Complex) + { if (Matrix->Error == spSINGULAR) return 0.0; - /* Find the bound on the size of the largest element over all - factorization. */ +/* Find the bound on the size of the largest element over all factorization. */ for (I = 1; I <= Matrix->Size; I++) - { - pDiag = Matrix->Diag[I]; + { pDiag = Matrix->Diag[I]; - /* Lower triangular matrix. */ +/* Lower triangular matrix. */ CMPLX_RECIPROCAL( cPivot, *pDiag ); - Mag = CMPLX_1_NORM( cPivot ); + Mag = CMPLX_INF_NORM( cPivot ); if (Mag > MaxRow) MaxRow = Mag; pElement = Matrix->FirstInRow[I]; while (pElement != pDiag) - { - Mag = CMPLX_1_NORM( *pElement ); + { Mag = CMPLX_INF_NORM( *pElement ); if (Mag > MaxRow) MaxRow = Mag; pElement = pElement->NextInRow; } - /* Upper triangular matrix. */ +/* Upper triangular matrix. */ pElement = Matrix->FirstInCol[I]; AbsColSum = 1.0; /* Diagonal of U is unity. */ while (pElement != pDiag) - { - AbsColSum += CMPLX_1_NORM( *pElement ); + { AbsColSum += CMPLX_INF_NORM( *pElement ); pElement = pElement->NextInCol; } if (AbsColSum > MaxCol) MaxCol = AbsColSum; } } else if (Matrix->Complex) - { - for (I = 1; I <= Matrix->Size; I++) - { - pElement = Matrix->FirstInCol[I]; + { for (I = 1; I <= Matrix->Size; I++) + { pElement = Matrix->FirstInCol[I]; while (pElement != NULL) - { - Mag = CMPLX_1_NORM( *pElement ); + { Mag = CMPLX_INF_NORM( *pElement ); if (Mag > Max) Max = Mag; pElement = pElement->NextInCol; } } return Max; } +#endif return MaxRow * MaxCol; } -/* - * MATRIX ROUNDOFF ERROR +/*! + * This routine, along with spLargestElement(), are used to gauge the + * stability of a factorization. See description of spLargestElement() + * for more information. * - * >>> Returns: - * Returns a bound on the magnitude of the largest element in E = A - LU. + * \return + * Returns a bound on the magnitude of the largest element in + * \f$ E = A - LU \f$. * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Pointer to the matrix. - * Rho (RealNumber) + * \param Rho * The bound on the magnitude of the largest element in any of the * reduced submatrices. This is the number computed by the function * spLargestElement() when given a factored matrix. If this number is * negative, the bound will be computed automatically. */ -RealNumber -spRoundoff(MatrixPtr Matrix, RealNumber Rho) +spREAL +spRoundoff( + spMatrix eMatrix, + spREAL Rho +) { - ElementPtr pElement; - int Count, I, MaxCount = 0; - RealNumber Reid, Gear; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register int Count, I, MaxCount = 0; +RealNumber Reid, Gear; - /* Begin `spRoundoff'. */ - assert( IS_SPARSE(Matrix) && IS_FACTORED(Matrix) ); +/* Begin `spRoundoff'. */ + ASSERT_IS_SPARSE( Matrix ); + ASSERT_NO_ERRORS( Matrix ); + ASSERT_IS_FACTORED( Matrix ); - /* Compute Barlow's bound if it is not given. */ - if (Rho < 0.0) Rho = spLargestElement( Matrix ); +/* Compute Barlow's bound if it is not given. */ + if (Rho < 0.0) Rho = spLargestElement( eMatrix ); - /* Find the maximum number of off-diagonals in L if not previously computed. */ +/* Find the maximum number of off-diagonals in L if not previously computed. */ if (Matrix->MaxRowCountInLowerTri < 0) - { - for (I = Matrix->Size; I > 0; I--) - { - pElement = Matrix->FirstInRow[I]; + { for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInRow[I]; Count = 0; while (pElement->Col < I) - { - Count++; + { Count++; pElement = pElement->NextInRow; } if (Count > MaxCount) MaxCount = Count; @@ -2091,7 +2116,7 @@ spRoundoff(MatrixPtr Matrix, RealNumber Rho) } else MaxCount = Matrix->MaxRowCountInLowerTri; - /* Compute error bound. */ +/* Compute error bound. */ Gear = 1.01*((MaxCount + 1) * Matrix->RelThreshold + 1.0) * SQR(MaxCount); Reid = 3.01 * Matrix->Size; @@ -2107,74 +2132,74 @@ spRoundoff(MatrixPtr Matrix, RealNumber Rho) - - + #if DOCUMENTATION -/* - * SPARSE ERROR MESSAGE +/*! + * This routine prints a short message describing the error error state + * of sparse. No message is produced if there is no error. + * The error state is cleared. * - * This routine prints a short message to a stream describing the error - * error state of sparse. No message is produced if there is no error. - * - * >>> Arguments: - * Matrix (char *) + * \param eMatrix * Matrix for which the error message is to be printed. - * Stream (FILE *) + * \param Stream * Stream to which the error message is to be printed. - * Originator (char *) + * \param Originator * Name of originator of error message. If NULL, `sparse' is used. * If zero-length string, no originator is printed. */ void -spErrorMessage(MatrixPtr Matrix, FILE *Stream, char *Originator) +spErrorMessage( + spMatrix eMatrix, + FILE *Stream, + char *Originator +) { - int Row, Col, Error; +int Row, Col, Error; - /* Begin `spErrorMessage'. */ - if (Matrix == NULL) +/* Begin `spErrorMessage'. */ + if (eMatrix == NULL) Error = spNO_MEMORY; else - { - assert(Matrix->ID == SPARSE_ID); - Error = Matrix->Error; + { ASSERT_IS_SPARSE( (MatrixPtr)eMatrix ); + Error = ((MatrixPtr)eMatrix)->Error; } if (Error == spOKAY) return; if (Originator == NULL) Originator = "sparse"; - if (Originator[0] != '\0') fprintf( Stream, "%s: ", Originator); + if (Stream == NULL) Stream = stderr; + if (Originator[0] != '\0') fprintf( Stream, "%s: ", Originator ); if (Error >= spFATAL) - fprintf( Stream, "fatal error, "); + fprintf( Stream, "fatal error: "); else - fprintf( Stream, "warning, "); - - /* Print particular error message. Do not use switch statement - * because error codes may not be unique. */ + fprintf( Stream, "warning: "); +/* + * Print particular error message. + * Do not use switch statement because error codes may not be unique. + */ if (Error == spPANIC) fprintf( Stream, "Sparse called improperly.\n"); else if (Error == spNO_MEMORY) fprintf( Stream, "insufficient memory available.\n"); + else if (Error == spMANGLED) + fprintf( Stream, "matrix is mangled.\n"); else if (Error == spSINGULAR) - { - spWhereSingular( Matrix, &Row, &Col ); + { spWhereSingular( eMatrix, &Row, &Col ); fprintf( Stream, "singular matrix detected at row %d and column %d.\n", Row, Col); } else if (Error == spZERO_DIAG) - { - spWhereSingular( Matrix, &Row, &Col ); + { spWhereSingular( eMatrix, &Row, &Col ); fprintf( Stream, "zero diagonal detected at row %d and column %d.\n", Row, Col); } else if (Error == spSMALL_PIVOT) - { - fprintf( Stream, - "unable to find a pivot that is larger than absolute threshold.\n"); - } - else - { - abort(); + { fprintf( Stream, + "unable to find a pivot that is larger than absolute threshold.\n"); } + else ABORT(); + + ((MatrixPtr)eMatrix)->Error = spOKAY; return; } #endif /* DOCUMENTATION */ diff --git a/src/maths/sparse/spalloc.c b/src/maths/sparse/spalloc.c deleted file mode 100644 index ceeb5ebc4..000000000 --- a/src/maths/sparse/spalloc.c +++ /dev/null @@ -1,885 +0,0 @@ -/* - * MATRIX ALLOCATION MODULE - * - * Author: Advising professor: - * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli - * UC Berkeley - * - * This file contains the allocation and deallocation routines for the - * sparse matrix routines. - * - * >>> User accessible functions contained in this file: - * spCreate - * spDestroy - * spError - * spWhereSingular - * spGetSize - * spSetReal - * spSetComplex - * spFillinCount - * spElementCount - * spOriginalCount - * - * >>> Other functions contained in this file: - * spcGetElement - * InitializeElementBlocks - * spcGetFillin - * RecordAllocation - * AllocateBlockOfAllocationList - * EnlargeMatrix - * ExpandTranslationArrays - */ - - -/* - * 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 -#include - -#define spINSIDE_SPARSE - -#include "spconfig.h" -#include "ngspice/spmatrix.h" -#include "spdefs.h" - -/* - * Function declarations - */ - -static void InitializeElementBlocks( MatrixPtr, int, int ); -static void RecordAllocation( MatrixPtr, void *); -static void AllocateBlockOfAllocationList( MatrixPtr ); - - - - -/* - * MATRIX ALLOCATION - * - * Allocates and initializes the data structures associated with a matrix. - * - * >>> Returned: - * A pointer to the matrix is returned cast into the form of a pointer to - * a character. This pointer is then passed and used by the other matrix - * routines to refer to a particular matrix. If an error occurs, the NULL - * pointer is returned. - * - * >>> Arguments: - * Size (int) - * Size of matrix or estimate of size of matrix if matrix is EXPANDABLE. - * Complex (int) - * Type of matrix. If Complex is 0 then the matrix is real, otherwise - * the matrix will be complex. Note that if the routines are not set up - * to handle the type of matrix requested, then a spPANIC error will occur. - * Further note that if a matrix will be both real and complex, it must - * be specified here as being complex. - * pError (int *) - * Returns error flag, needed because function spError() will not work - * correctly if spCreate() returns NULL. - * - * >>> Local variables: - * AllocatedSize (int) - * The size of the matrix being allocated. - * Matrix (MatrixPtr) - * A pointer to the matrix frame being created. - * - * >>> Possible errors: - * spNO_MEMORY - * spPANIC - * Error is cleared in this routine. - */ - -MatrixPtr -spCreate(int Size, int Complex, int *pError) -{ - unsigned SizePlusOne; - MatrixPtr Matrix; - int I; - int AllocatedSize; - - /* Begin `spCreate'. */ - /* Clear error flag. */ - *pError = spOKAY; - - /* Test for valid size. */ -#if EXPANDABLE - if (Size < 0) { - *pError = spPANIC; - return NULL; - } -#else - if (Size <= 0) { - *pError = spPANIC; - return NULL; - } -#endif - - -#if 0 /* pn: skipped for cider */ - /* Test for valid type. */ - if (!Complex) { - *pError = spPANIC; - return NULL; - } -#endif - - /* Create Matrix. */ - AllocatedSize = MAX( Size, MINIMUM_ALLOCATED_SIZE ); - SizePlusOne = (unsigned)(AllocatedSize + 1); - - if ((Matrix = SP_MALLOC(struct MatrixFrame, 1)) == NULL) { - *pError = spNO_MEMORY; - return NULL; - } - - /* Initialize matrix */ - Matrix->ID = SPARSE_ID; - Matrix->Complex = Complex; - Matrix->PreviousMatrixWasComplex = Complex; - Matrix->Factored = NO; - Matrix->Elements = 0; - Matrix->Error = *pError; - Matrix->Originals = 0; - Matrix->Fillins = 0; - Matrix->Reordered = NO; - Matrix->NeedsOrdering = YES; - Matrix->NumberOfInterchangesIsOdd = NO; - Matrix->Partitioned = NO; - Matrix->RowsLinked = NO; - Matrix->InternalVectorsAllocated = NO; - Matrix->SingularCol = 0; - Matrix->SingularRow = 0; - Matrix->Size = Size; - Matrix->AllocatedSize = AllocatedSize; - Matrix->ExtSize = Size; - Matrix->AllocatedExtSize = AllocatedSize; - Matrix->CurrentSize = 0; - Matrix->ExtToIntColMap = NULL; - Matrix->ExtToIntRowMap = NULL; - Matrix->IntToExtColMap = NULL; - Matrix->IntToExtRowMap = NULL; - Matrix->MarkowitzRow = NULL; - Matrix->MarkowitzCol = NULL; - Matrix->MarkowitzProd = NULL; - Matrix->DoCmplxDirect = NULL; - Matrix->DoRealDirect = NULL; - Matrix->Intermediate = NULL; - Matrix->RelThreshold = DEFAULT_THRESHOLD; - Matrix->AbsThreshold = 0.0; - - Matrix->TopOfAllocationList = NULL; - Matrix->RecordsRemaining = 0; - Matrix->ElementsRemaining = 0; - Matrix->FillinsRemaining = 0; - - RecordAllocation( Matrix, Matrix ); - if (Matrix->Error == spNO_MEMORY) goto MemoryError; - - /* Take out the trash. */ - Matrix->TrashCan.Real = 0.0; - Matrix->TrashCan.Imag = 0.0; - Matrix->TrashCan.Row = 0; - Matrix->TrashCan.Col = 0; - Matrix->TrashCan.NextInRow = NULL; - Matrix->TrashCan.NextInCol = NULL; -#if INITIALIZE - Matrix->TrashCan.pInitInfo = NULL; -#endif - - /* Allocate space in memory for Diag pointer vector. */ - SP_CALLOC( Matrix->Diag, ElementPtr, SizePlusOne); - if (Matrix->Diag == NULL) - goto MemoryError; - - /* Allocate space in memory for FirstInCol pointer vector. */ - SP_CALLOC( Matrix->FirstInCol, ElementPtr, SizePlusOne); - if (Matrix->FirstInCol == NULL) - goto MemoryError; - - /* Allocate space in memory for FirstInRow pointer vector. */ - SP_CALLOC( Matrix->FirstInRow, ElementPtr, SizePlusOne); - if (Matrix->FirstInRow == NULL) - goto MemoryError; - - /* Allocate space in memory for IntToExtColMap vector. */ - if (( Matrix->IntToExtColMap = SP_MALLOC(int, SizePlusOne)) == NULL) - goto MemoryError; - - /* Allocate space in memory for IntToExtRowMap vector. */ - if (( Matrix->IntToExtRowMap = SP_MALLOC(int, SizePlusOne)) == NULL) - goto MemoryError; - - /* Initialize MapIntToExt vectors. */ - for (I = 1; I <= AllocatedSize; I++) - { - Matrix->IntToExtRowMap[I] = I; - Matrix->IntToExtColMap[I] = I; - } - -#if TRANSLATE - /* Allocate space in memory for ExtToIntColMap vector. */ - if (( Matrix->ExtToIntColMap = SP_MALLOC(int, SizePlusOne)) == NULL) - goto MemoryError; - - /* Allocate space in memory for ExtToIntRowMap vector. */ - if (( Matrix->ExtToIntRowMap = SP_MALLOC(int, SizePlusOne)) == NULL) - goto MemoryError; - - /* Initialize MapExtToInt vectors. */ - for (I = 1; I <= AllocatedSize; I++) { - Matrix->ExtToIntColMap[I] = -1; - Matrix->ExtToIntRowMap[I] = -1; - } - Matrix->ExtToIntColMap[0] = 0; - Matrix->ExtToIntRowMap[0] = 0; -#endif - - /* Allocate space for fill-ins and initial set of elements. */ - InitializeElementBlocks( Matrix, SPACE_FOR_ELEMENTS*AllocatedSize, - SPACE_FOR_FILL_INS*AllocatedSize ); - if (Matrix->Error == spNO_MEMORY) - goto MemoryError; - - return Matrix; - - MemoryError: - - /* Deallocate matrix and return no pointer to matrix if there is not enough - memory. */ - *pError = spNO_MEMORY; - spDestroy(Matrix); - return NULL; -} - - - - - - - - - -/* - * ELEMENT ALLOCATION - * - * This routine allocates space for matrix elements. It requests large blocks - * of storage from the system and doles out individual elements as required. - * This technique, as opposed to allocating elements individually, tends to - * speed the allocation process. - * - * >>> Returned: - * A pointer to an element. - * - * >>> Arguments: - * Matrix (MatrixPtr) - * Pointer to matrix. - * - * >>> Local variables: - * pElement (ElementPtr) - * A pointer to the first element in the group of elements being allocated. - * - * >>> Possible errors: - * spNO_MEMORY - */ - -ElementPtr -spcGetElement(MatrixPtr Matrix) -{ - ElementPtr pElements; - - /* Begin `spcGetElement'. */ - -#if !COMBINE || STRIP || LINT - /* Allocate block of MatrixElements if necessary. */ - if (Matrix->ElementsRemaining == 0) { - pElements = SP_MALLOC(struct MatrixElement, ELEMENTS_PER_ALLOCATION); - RecordAllocation( Matrix, pElements ); - if (Matrix->Error == spNO_MEMORY) return NULL; - Matrix->ElementsRemaining = ELEMENTS_PER_ALLOCATION; - Matrix->NextAvailElement = pElements; - } -#endif - -#if COMBINE || STRIP || LINT - if (Matrix->ElementsRemaining == 0) - { - pListNode = Matrix->LastElementListNode; - - /* First see if there are any stripped elements left. */ - if (pListNode->Next != NULL) { - Matrix->LastElementListNode = pListNode = pListNode->Next; - Matrix->ElementsRemaining = pListNode->NumberOfElementsInList; - Matrix->NextAvailElement = pListNode->pElementList; - } else { - /* Allocate block of elements. */ - pElements = SP_MALLOC(struct MatrixElement, ELEMENTS_PER_ALLOCATION); - RecordAllocation( Matrix, pElements ); - if (Matrix->Error == spNO_MEMORY) return NULL; - Matrix->ElementsRemaining = ELEMENTS_PER_ALLOCATION; - Matrix->NextAvailElement = pElements; - - /* Allocate an element list structure. */ - pListNode->Next = SP_MALLOC(struct ElementListNodeStruct,1); - RecordAllocation( Matrix, pListNode->Next ); - if (Matrix->Error == spNO_MEMORY) - return NULL; - Matrix->LastElementListNode = pListNode = pListNode->Next; - - pListNode->pElementList = pElements; - pListNode->NumberOfElementsInList = ELEMENTS_PER_ALLOCATION; - pListNode->Next = NULL; - } - } -#endif - - /* Update Element counter and return pointer to Element. */ - Matrix->ElementsRemaining--; - return Matrix->NextAvailElement++; - -} - - - - - - - - -/* - * ELEMENT ALLOCATION INITIALIZATION - * - * This routine allocates space for matrix fill-ins and an initial - * set of elements. Besides being faster than allocating space for - * elements one at a time, it tends to keep the fill-ins physically - * close to the other matrix elements in the computer memory. This - * keeps virtual memory paging to a minimum. - * - * >>> Arguments: - * Matrix (MatrixPtr) - * Pointer to the matrix. - * InitialNumberOfElements (int) - * This number is used as the size of the block of memory, in - * MatrixElements, reserved for elements. If more than this number of - * elements are generated, then more space is allocated later. - * NumberOfFillinsExpected (int) - * This number is used as the size of the block of memory, in - * MatrixElements, reserved for fill-ins. If more than this number of - * fill-ins are generated, then more space is allocated, but they may - * not be physically close in computer's memory. - * - * >>> Local variables: - * pElement (ElementPtr) - * A pointer to the first element in the group of elements being allocated. - * - * >>> Possible errors: - * spNO_MEMORY */ - -static void -InitializeElementBlocks(MatrixPtr Matrix, int InitialNumberOfElements, - int NumberOfFillinsExpected) -{ - ElementPtr pElement; - - /* Begin `InitializeElementBlocks'. */ - - /* Allocate block of MatrixElements for elements. */ - pElement = SP_MALLOC(struct MatrixElement, InitialNumberOfElements); - RecordAllocation( Matrix, pElement ); - if (Matrix->Error == spNO_MEMORY) return; - Matrix->ElementsRemaining = InitialNumberOfElements; - Matrix->NextAvailElement = pElement; - - /* Allocate an element list structure. */ - Matrix->FirstElementListNode = SP_MALLOC(struct ElementListNodeStruct,1); - RecordAllocation( Matrix, Matrix->FirstElementListNode ); - if (Matrix->Error == spNO_MEMORY) return; - Matrix->LastElementListNode = Matrix->FirstElementListNode; - - Matrix->FirstElementListNode->pElementList = pElement; - Matrix->FirstElementListNode->NumberOfElementsInList = - InitialNumberOfElements; - Matrix->FirstElementListNode->Next = NULL; - - /* Allocate block of MatrixElements for fill-ins. */ - pElement = SP_MALLOC(struct MatrixElement, NumberOfFillinsExpected); - RecordAllocation( Matrix, pElement ); - if (Matrix->Error == spNO_MEMORY) return; - Matrix->FillinsRemaining = NumberOfFillinsExpected; - Matrix->NextAvailFillin = pElement; - - /* Allocate a fill-in list structure. */ - Matrix->FirstFillinListNode = SP_MALLOC(struct FillinListNodeStruct,1); - RecordAllocation( Matrix, Matrix->FirstFillinListNode ); - if (Matrix->Error == spNO_MEMORY) return; - Matrix->LastFillinListNode = Matrix->FirstFillinListNode; - - Matrix->FirstFillinListNode->pFillinList = pElement; - Matrix->FirstFillinListNode->NumberOfFillinsInList =NumberOfFillinsExpected; - Matrix->FirstFillinListNode->Next = NULL; - - return; -} - - - - - - - - - - -/* - * FILL-IN ALLOCATION - * - * This routine allocates space for matrix fill-ins. It requests - * large blocks of storage from the system and doles out individual - * elements as required. This technique, as opposed to allocating - * elements individually, tends to speed the allocation process. - * - * >>> Returned: - * A pointer to the fill-in. - * - * >>> Arguments: - * Matrix (MatrixPtr) - * Pointer to matrix. - * - * >>> Possible errors: - * spNO_MEMORY */ - -ElementPtr -spcGetFillin(MatrixPtr Matrix) -{ - /* Begin `spcGetFillin'. */ - -#if !STRIP || LINT - if (Matrix->FillinsRemaining == 0) - return spcGetElement( Matrix ); -#endif -#if STRIP || LINT - - if (Matrix->FillinsRemaining == 0) { - pListNode = Matrix->LastFillinListNode; - - /* First see if there are any stripped fill-ins left. */ - if (pListNode->Next != NULL) { - Matrix->LastFillinListNode = pListNode = pListNode->Next; - Matrix->FillinsRemaining = pListNode->NumberOfFillinsInList; - Matrix->NextAvailFillin = pListNode->pFillinList; - } else { - /* Allocate block of fill-ins. */ - pFillins = SP_MALLOC(struct MatrixElement, ELEMENTS_PER_ALLOCATION); - RecordAllocation( Matrix, pFillins ); - if (Matrix->Error == spNO_MEMORY) return NULL; - Matrix->FillinsRemaining = ELEMENTS_PER_ALLOCATION; - Matrix->NextAvailFillin = pFillins; - - /* Allocate a fill-in list structure. */ - pListNode->Next = SP_MALLOC(struct FillinListNodeStruct,1); - RecordAllocation( Matrix, pListNode->Next ); - if (Matrix->Error == spNO_MEMORY) return NULL; - Matrix->LastFillinListNode = pListNode = pListNode->Next; - - pListNode->pFillinList = pFillins; - pListNode->NumberOfFillinsInList = ELEMENTS_PER_ALLOCATION; - pListNode->Next = NULL; - } - } -#endif - - /* Update Fill-in counter and return pointer to Fill-in. */ - Matrix->FillinsRemaining--; - return Matrix->NextAvailFillin++; -} - - - - - - - - - -/* - * RECORD A MEMORY ALLOCATION - * - * This routine is used to record all memory allocations so that the - * memory can be freed later. - * - * >>> Arguments: - * Matrix (MatrixPtr) - * Pointer to the matrix. - * AllocatedPtr (void *) - * The pointer returned by tmalloc or calloc. These pointers are - * saved in a list so that they can be easily freed. - * - * >>> Possible errors: - * spNO_MEMORY */ - -static void -RecordAllocation(MatrixPtr Matrix, void *AllocatedPtr ) -{ - /* Begin `RecordAllocation'. */ - /* If Allocated pointer is NULL, assume that tmalloc returned a - * NULL pointer, which indicates a spNO_MEMORY error. */ - if (AllocatedPtr == NULL) { - Matrix->Error = spNO_MEMORY; - return; - } - - /* Allocate block of MatrixElements if necessary. */ - if (Matrix->RecordsRemaining == 0) { - AllocateBlockOfAllocationList( Matrix ); - if (Matrix->Error == spNO_MEMORY) { - SP_FREE(AllocatedPtr); - return; - } - } - - /* Add Allocated pointer to Allocation List. */ - (++Matrix->TopOfAllocationList)->AllocatedPtr = AllocatedPtr; - Matrix->RecordsRemaining--; - return; -} - - - - - - - - -/* - * ADD A BLOCK OF SLOTS TO ALLOCATION LIST - * - * This routine increases the size of the allocation list. - * - * >>> Arguments: - * Matrix (MatrixPtr) - * Pointer to the matrix. - * - * >>> Local variables: - * ListPtr (AllocationListPtr) - * Pointer to the list that contains the pointers to segments of - * memory that were allocated by the operating system for the - * current matrix. - * - * >>> Possible errors: - * spNO_MEMORY */ - -static void -AllocateBlockOfAllocationList(MatrixPtr Matrix) -{ - int I; - AllocationListPtr ListPtr; - - /* Begin `AllocateBlockOfAllocationList'. */ - /* Allocate block of records for allocation list. */ - ListPtr = SP_MALLOC(struct AllocationRecord, (ELEMENTS_PER_ALLOCATION+1)); - if (ListPtr == NULL) { - Matrix->Error = spNO_MEMORY; - return; - } - - /* String entries of allocation list into singly linked list. - List is linked such that any record points to the one before - it. */ - - ListPtr->NextRecord = Matrix->TopOfAllocationList; - Matrix->TopOfAllocationList = ListPtr; - ListPtr += ELEMENTS_PER_ALLOCATION; - for (I = ELEMENTS_PER_ALLOCATION; I > 0; I--) { - ListPtr->NextRecord = ListPtr - 1; - ListPtr--; - } - - /* Record allocation of space for allocation list on allocation list. */ - Matrix->TopOfAllocationList->AllocatedPtr = (void *)ListPtr; - Matrix->RecordsRemaining = ELEMENTS_PER_ALLOCATION; - - return; -} - - - - - - - - -/* - * MATRIX DEALLOCATION - * - * Deallocates pointers and elements of Matrix. - * - * >>> Arguments: - * Matrix (void *) - * Pointer to the matrix frame which is to be removed from memory. - * - * >>> Local variables: - * ListPtr (AllocationListPtr) - * Pointer into the linked list of pointers to allocated data structures. - * Points to pointer to structure to be freed. - * NextListPtr (AllocationListPtr) - * Pointer into the linked list of pointers to allocated data structures. - * Points to the next pointer to structure to be freed. This is needed - * because the data structure to be freed could include the current node - * in the allocation list. - */ - -void -spDestroy(MatrixPtr Matrix) -{ - AllocationListPtr ListPtr, NextListPtr; - - - /* Begin `spDestroy'. */ - assert( IS_SPARSE( Matrix ) ); - - /* Deallocate the vectors that are located in the matrix frame. */ - SP_FREE( Matrix->IntToExtColMap ); - SP_FREE( Matrix->IntToExtRowMap ); - SP_FREE( Matrix->ExtToIntColMap ); - SP_FREE( Matrix->ExtToIntRowMap ); - SP_FREE( Matrix->Diag ); - SP_FREE( Matrix->FirstInRow ); - SP_FREE( Matrix->FirstInCol ); - SP_FREE( Matrix->MarkowitzRow ); - SP_FREE( Matrix->MarkowitzCol ); - SP_FREE( Matrix->MarkowitzProd ); - SP_FREE( Matrix->DoCmplxDirect ); - SP_FREE( Matrix->DoRealDirect ); - SP_FREE( Matrix->Intermediate ); - - /* Sequentially step through the list of allocated pointers - * freeing pointers along the way. */ - ListPtr = Matrix->TopOfAllocationList; - while (ListPtr != NULL) { - NextListPtr = ListPtr->NextRecord; - if ((void *) ListPtr == ListPtr->AllocatedPtr) { - SP_FREE( ListPtr ); - } else { - SP_FREE( ListPtr->AllocatedPtr ); - } - ListPtr = NextListPtr; - } - return; -} - - - - - - - -/* - * RETURN MATRIX ERROR STATUS - * - * This function is used to determine the error status of the given - * matrix. - * - * >>> Returned: - * The error status of the given matrix. - * - * >>> Arguments: - * Matrix (void *) - * The matrix for which the error status is desired. */ -int -spError(MatrixPtr Matrix ) -{ - /* Begin `spError'. */ - - if (Matrix != NULL) { - assert(Matrix->ID == SPARSE_ID); - return Matrix->Error; - } else { - /* This error may actually be spPANIC, no way to tell. */ - return spNO_MEMORY; - } -} - - - - - - - - - -/* - * WHERE IS MATRIX SINGULAR - * - * This function returns the row and column number where the matrix was - * detected as singular or where a zero was detected on the diagonal. - * - * >>> Arguments: - * Matrix (void *) - * The matrix for which the error status is desired. - * pRow (int *) - * The row number. - * pCol (int *) - * The column number. - */ - -void -spWhereSingular(MatrixPtr Matrix, int *pRow, int *pCol) -{ - /* Begin `spWhereSingular'. */ - assert( IS_SPARSE( Matrix ) ); - - if (Matrix->Error == spSINGULAR || Matrix->Error == spZERO_DIAG) - { - *pRow = Matrix->SingularRow; - *pCol = Matrix->SingularCol; - } - else *pRow = *pCol = 0; - return; -} - - - - - - -/* - * MATRIX SIZE - * - * Returns the size of the matrix. Either the internal or external size of - * the matrix is returned. - * - * >>> Arguments: - * Matrix (void *) - * Pointer to matrix. - * External (int) - * If External is set TRUE, the external size , i.e., the value of the - * largest external row or column number encountered is returned. - * Otherwise the TRUE size of the matrix is returned. These two sizes - * may differ if the TRANSLATE option is set TRUE. - */ - -int -spGetSize(MatrixPtr Matrix, int External) -{ - /* Begin `spGetSize'. */ - assert( IS_SPARSE( Matrix ) ); - -#if TRANSLATE - if (External) - return Matrix->ExtSize; - else - return Matrix->Size; -#else - return Matrix->Size; -#endif -} - - - - - - - - -/* - * SET MATRIX COMPLEX OR REAL - * - * Forces matrix to be either real or complex. - * - * >>> Arguments: - * Matrix (void *) - * Pointer to matrix. - */ - -void -spSetReal(MatrixPtr Matrix) -{ - /* Begin `spSetReal'. */ - - assert( IS_SPARSE( Matrix )); - Matrix->Complex = NO; - return; -} - - -void -spSetComplex(MatrixPtr Matrix) -{ - /* Begin `spSetComplex'. */ - - assert( IS_SPARSE( Matrix )); - Matrix->Complex = YES; - return; -} - - - - - - - - - -/* - * ELEMENT, FILL-IN OR ORIGINAL COUNT - * - * Two functions used to return simple statistics. Either the number - * of total elements, or the number of fill-ins, or the number - * of original elements can be returned. - * - * >>> Arguments: - * Matrix (void *) - * Pointer to matrix. - */ - -int -spFillinCount(MatrixPtr Matrix) -{ - /* Begin `spFillinCount'. */ - - assert( IS_SPARSE( Matrix ) ); - return Matrix->Fillins; -} - - -int -spElementCount(MatrixPtr Matrix) -{ - /* Begin `spElementCount'. */ - - assert( IS_SPARSE( Matrix ) ); - return Matrix->Elements; -} - -int -spOriginalCount(MatrixPtr Matrix) -{ - /* Begin `spOriginalCount'. */ - - assert( IS_SPARSE( Matrix ) ); - return Matrix->Originals; -} diff --git a/src/maths/sparse/spbuild.c b/src/maths/sparse/spbuild.c deleted file mode 100644 index 0536bf624..000000000 --- a/src/maths/sparse/spbuild.c +++ /dev/null @@ -1,1206 +0,0 @@ -/* - * MATRIX BUILD MODULE - * - * Author: Advising professor: - * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli - * UC Berkeley - * - * This file contains the routines associated with clearing, loading and - * preprocessing the matrix for the sparse matrix routines. - * - * >>> User accessible functions contained in this file: - * spClear - * spGetElement - * spFindElement - * spGetAdmittance - * spGetQuad - * spGetOnes - * spInstallInitInfo - * spGetInitInfo - * spInitialize - * - * >>> Other functions contained in this file: - * spcFindElementInCol - * Translate - * spcCreateElement - * spcLinkRows - * EnlargeMatrix - * ExpandTranslationArrays - */ - - -/* - * 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 - -#define spINSIDE_SPARSE -#include "spconfig.h" -#include "ngspice/spmatrix.h" -#include "spdefs.h" - - - - - -/* - * Function declarations - */ -static void Translate( MatrixPtr, int*, int* ); -static void EnlargeMatrix( MatrixPtr, int ); -static void ExpandTranslationArrays( MatrixPtr, int ); - - - - - -/* - * CLEAR MATRIX - * - * Sets every element of the matrix to zero and clears the error flag. - * - * >>> Arguments: - * Matrix (char *) - * Pointer to matrix that is to be cleared. - * - * >>> Local variables: - * pElement (ElementPtr) - * A pointer to the element being cleared. - */ - -void -spClear(MatrixPtr Matrix) -{ - ElementPtr pElement; - int I; - - /* Begin `spClear'. */ - assert( IS_SPARSE( Matrix ) ); - - /* Clear matrix. */ - if (Matrix->PreviousMatrixWasComplex || Matrix->Complex) - { - for (I = Matrix->Size; I > 0; I--) - { - pElement = Matrix->FirstInCol[I]; - while (pElement != NULL) - { - pElement->Real = 0.0; - pElement->Imag = 0.0; - pElement = pElement->NextInCol; - } - } - } - else - { - for (I = Matrix->Size; I > 0; I--) - { - pElement = Matrix->FirstInCol[I]; - while (pElement != NULL) - { - pElement->Real = 0.0; - pElement = pElement->NextInCol; - } - } - } - - /* Empty the trash. */ - Matrix->TrashCan.Real = 0.0; - Matrix->TrashCan.Imag = 0.0; - - Matrix->Error = spOKAY; - Matrix->Factored = NO; - Matrix->SingularCol = 0; - Matrix->SingularRow = 0; - Matrix->PreviousMatrixWasComplex = Matrix->Complex; - return; -} - - - - -/* - * SINGLE ELEMENT LOCATION IN MATRIX BY INDEX - * - * Finds element [Row,Col] and returns a pointer to it. If element is - * not found then it is created and spliced into matrix. This routine - * is only to be used after spCreate() and before spMNA_Preorder(), - * spFactor() or spOrderAndFactor(). Returns a pointer to the - * Real portion of a MatrixElement. This pointer is later used by - * spADD_xxx_ELEMENT to directly access element. - * - * >>> Returns: - * Returns a pointer to the element. This pointer is then used to directly - * access the element during successive builds. - * - * >>> Arguments: - * Matrix (char *) - * Pointer to the matrix that the element is to be added to. - * Row (int) - * Row index for element. Must be in the range of [0..Size] unless - * the options EXPANDABLE or TRANSLATE are used. Elements placed in - * row zero are discarded. In no case may Row be less than zero. - * Col (int) - * Column index for element. Must be in the range of [0..Size] unless - * the options EXPANDABLE or TRANSLATE are used. Elements placed in - * column zero are discarded. In no case may Col be less than zero. - * - * >>> Local variables: - * pElement (RealNumber *) - * Pointer to the element. - * - * >>> Possible errors: - * spNO_MEMORY - * Error is not cleared in this routine. - */ - -RealNumber * -spFindElement(MatrixPtr Matrix, int Row, int Col) -{ -ElementPtr pElement; - -/* Begin `spFindElement'. */ - assert( IS_SPARSE( Matrix ) && Row >= 0 && Col >= 0 ); - - if ((Row == 0) || (Col == 0)) - return &Matrix->TrashCan.Real; - -#if TRANSLATE - Translate( Matrix, &Row, &Col ); - if (Matrix->Error == spNO_MEMORY) return NULL; -#endif - -#if ! TRANSLATE - assert(Row <= Matrix->Size && Col <= Matrix->Size); -#endif - -/* - * The condition part of the following if statement tests to see if the - * element resides along the diagonal, if it does then it tests to see - * if the element has been created yet (Diag pointer not NULL). The - * pointer to the element is then assigned to Element after it is cast - * into a pointer to a RealNumber. This casting makes the pointer into - * a pointer to Real. This statement depends on the fact that Real - * is the first record in the MatrixElement structure. - */ - - if ((Row != Col) || ((pElement = Matrix->Diag[Row]) == NULL)) - { -/* - * Element does not exist or does not reside along diagonal. Search - * column for element. As in the if statement above, the pointer to the - * element which is returned by spcFindElementInCol is cast into a - * pointer to Real, a RealNumber. - */ - pElement = spcFindElementInCol( Matrix, - &(Matrix->FirstInCol[Col]), - Row, Col, NO ); - } - return & pElement->Real; -} - - - -/* - * SINGLE ELEMENT ADDITION TO MATRIX BY INDEX - * - * Finds element [Row,Col] and returns a pointer to it. If element is - * not found then it is created and spliced into matrix. This routine - * is only to be used after spCreate() and before spMNA_Preorder(), - * spFactor() or spOrderAndFactor(). Returns a pointer to the - * Real portion of a MatrixElement. This pointer is later used by - * spADD_xxx_ELEMENT to directly access element. - * - * >>> Returns: - * Returns a pointer to the element. This pointer is then used to directly - * access the element during successive builds. - * - * >>> Arguments: - * Matrix (char *) - * Pointer to the matrix that the element is to be added to. - * Row (int) - * Rowstrchr for element. Must be in the range of [0..Size] unless - * the options EXPANDABLE or TRANSLATE are used. Elements placed in - * row zero are discarded. In no case may Row be less than zero. - * Col (int) - * Columnstrchr for element. Must be in the range of [0..Size] unless - * the options EXPANDABLE or TRANSLATE are used. Elements placed in - * column zero are discarded. In no case may Col be less than zero. - * - * >>> Local variables: - * pElement (RealNumber *) - * Pointer to the element. - * - * >>> Possible errors: - * spNO_MEMORY - * Error is not cleared in this routine. - */ - -RealNumber * -spGetElement(MatrixPtr Matrix, int Row, int Col) -{ - ElementPtr pElement; - - /* Begin `spGetElement'. */ - assert( IS_SPARSE( Matrix ) && Row >= 0 && Col >= 0 ); - - if ((Row == 0) || (Col == 0)) - return &Matrix->TrashCan.Real; - -#if !TRANSLATE - assert(Matrix->NeedsOrdering); -#endif - -#if TRANSLATE - Translate( Matrix, &Row, &Col ); - if (Matrix->Error == spNO_MEMORY) return NULL; -#endif - -#if !TRANSLATE -#if !EXPANDABLE - assert(Row <= Matrix->Size && Col <= Matrix->Size); -#endif - -#if EXPANDABLE - /* Re-size Matrix if necessary. */ - if ((Row > Matrix->Size) || (Col > Matrix->Size)) - EnlargeMatrix( Matrix, MAX(Row, Col) ); - if (Matrix->Error == spNO_MEMORY) return NULL; -#endif -#endif - - /* The condition part of the following if statement tests to see - * if the element resides along the diagonal, if it does then it - * tests to see if the element has been created yet (Diag pointer - * not NULL). The pointer to the element is then assigned to - * Element after it is cast into a pointer to a RealNumber. This - * casting makes the pointer into a pointer to Real. This - * statement depends on the fact that Real is the first record in - * the MatrixElement structure. */ - - if ((Row != Col) || ((pElement = Matrix->Diag[Row]) == NULL)) - { - /* Element does not exist or does not reside along diagonal. - * Search column for element. As in the if statement above, - * the pointer to the element which is returned by - * spcFindElementInCol is cast into a pointer to Real, a - * RealNumber. */ - pElement = spcFindElementInCol( Matrix, - &(Matrix->FirstInCol[Col]), - Row, Col, YES ); - } - return & pElement->Real; -} - - - - - - - - - - - -/* - * FIND ELEMENT BY SEARCHING COLUMN - * - * Searches column starting at element specified at PtrAddr and finds element - * in Row. If Element does not exists, it is created. The pointer to the - * element is returned. - * - * >>> Returned: - * A pointer to the desired element: - * - * >>> Arguments: - * Matrix (MatrixPtr) - * Pointer to Matrix. - * LastAddr (ElementPtr *) - * Address of pointer that initially points to the element in Col at which - * the search is started. The pointer in this location may be changed if - * a fill-in is required in and adjacent element. For this reason it is - * important that LastAddr be the address of a FirstInCol or a NextInCol - * rather than a temporary variable. - * Row (int) - * Row being searched for. - * Col (int) - * Column being searched. - * CreateIfMissing (int) - * Indicates what to do if element is not found, create one or return a - * NULL pointer. - * - * Local variables: - * pElement (ElementPtr) - * Pointer used to search through matrix. - */ - -ElementPtr -spcFindElementInCol(MatrixPtr Matrix, ElementPtr *LastAddr, - int Row, int Col, int CreateIfMissing) -{ - ElementPtr pElement; - - /* Begin `spcFindElementInCol'. */ - pElement = *LastAddr; - - /* Search for element. */ - while (pElement != NULL) - { - if (pElement->Row < Row) - { - /* Have not reached element yet. */ - LastAddr = &(pElement->NextInCol); - pElement = pElement->NextInCol; - } - else if (pElement->Row == Row) - { - /* Reached element. */ - return pElement; - } - else break; /* while loop */ - } - - /* Element does not exist and must be created. */ - if (CreateIfMissing) - return spcCreateElement( Matrix, Row, Col, LastAddr, NO ); - else - return NULL; -} - - - - - - - - -#if TRANSLATE - -/* - * TRANSLATE EXTERNAL INDICES TO INTERNAL - * - * Convert external row and column numbers to internal row and column numbers. - * Also updates Ext/Int maps. - * - * - * >>> Arguments: - * Matrix (MatrixPtr) - * Pointer to the matrix. - * Row (int *) - * Upon entry Row is either a external row number or an external node - * number. Upon return, the internal equivalent is supplied. - * Col (int *) - * Upon entry Column is either a external column number or an external node - * number. Upon return, the internal equivalent is supplied. - * - * >>> Local variables: - * ExtCol (int) - * Temporary variable used to hold the external column or node number - * during the external to internal column number translation. - * ExtRow (int) - * Temporary variable used to hold the external row or node number during - * the external to internal row number translation. - * IntCol (int) - * Temporary variable used to hold the internal column or node number - * during the external to internal column number translation. - * IntRow (int) - * Temporary variable used to hold the internal row or node number during - * the external to internal row number translation. - */ - -static void -Translate(MatrixPtr Matrix, int *Row, int *Col) -{ - int IntRow, IntCol, ExtRow, ExtCol; - - /* Begin `Translate'. */ - ExtRow = *Row; - ExtCol = *Col; - - /* Expand translation arrays if necessary. */ - if ((ExtRow > Matrix->AllocatedExtSize) || - (ExtCol > Matrix->AllocatedExtSize)) - { - ExpandTranslationArrays( Matrix, MAX(ExtRow, ExtCol) ); - if (Matrix->Error == spNO_MEMORY) return; - } - - /* Set ExtSize if necessary. */ - if ((ExtRow > Matrix->ExtSize) || (ExtCol > Matrix->ExtSize)) - Matrix->ExtSize = MAX(ExtRow, ExtCol); - - /* Translate external row or node number to internal row or node number. */ - if ((IntRow = Matrix->ExtToIntRowMap[ExtRow]) == -1) - { - Matrix->ExtToIntRowMap[ExtRow] = ++Matrix->CurrentSize; - Matrix->ExtToIntColMap[ExtRow] = Matrix->CurrentSize; - IntRow = Matrix->CurrentSize; - -#if !EXPANDABLE - assert(IntRow <= Matrix->Size); -#endif - -#if EXPANDABLE - /* Re-size Matrix if necessary. */ - if (IntRow > Matrix->Size) - EnlargeMatrix( Matrix, IntRow ); - if (Matrix->Error == spNO_MEMORY) return; -#endif - - Matrix->IntToExtRowMap[IntRow] = ExtRow; - Matrix->IntToExtColMap[IntRow] = ExtRow; - } - - /* Translate external column or node number to internal column or node number.*/ - if ((IntCol = Matrix->ExtToIntColMap[ExtCol]) == -1) - { - Matrix->ExtToIntRowMap[ExtCol] = ++Matrix->CurrentSize; - Matrix->ExtToIntColMap[ExtCol] = Matrix->CurrentSize; - IntCol = Matrix->CurrentSize; - -#if !EXPANDABLE - assert(IntCol <= Matrix->Size); -#endif - -#if EXPANDABLE - /* Re-size Matrix if necessary. */ - if (IntCol > Matrix->Size) - EnlargeMatrix( Matrix, IntCol ); - if (Matrix->Error == spNO_MEMORY) return; -#endif - - Matrix->IntToExtRowMap[IntCol] = ExtCol; - Matrix->IntToExtColMap[IntCol] = ExtCol; - } - - *Row = IntRow; - *Col = IntCol; - return; -} -#endif - - - - - - -#if QUAD_ELEMENT -/* - * ADDITION OF ADMITTANCE TO MATRIX BY INDEX - * - * Performs same function as spGetElement except rather than one - * element, all four Matrix elements for a floating component are - * added. This routine also works if component is grounded. Positive - * elements are placed at [Node1,Node2] and [Node2,Node1]. This - * routine is only to be used after spCreate() and before - * spMNA_Preorder(), spFactor() or spOrderAndFactor(). - * - * >>> Returns: - * Error code. - * - * >>> Arguments: - * Matrix (char *) - * Pointer to the matrix that component is to be entered in. - * Node1 (int) - * Row and column indices for elements. Must be in the range of [0..Size] - * unless the options EXPANDABLE or TRANSLATE are used. Node zero is the - * ground node. In no case may Node1 be less than zero. - * Node2 (int) - * Row and column indices for elements. Must be in the range of [0..Size] - * unless the options EXPANDABLE or TRANSLATE are used. Node zero is the - * ground node. In no case may Node2 be less than zero. - * Template (struct spTemplate *) - * Collection of pointers to four elements that are later used to directly - * address elements. User must supply the template, this routine will - * fill it. - * - * Possible errors: - * spNO_MEMORY - * Error is not cleared in this routine. - */ - -int -spGetAdmittance(MatrixPtr Matrix, int Node1, int Node2, - struct spTemplate *Template) -{ - /* Begin `spGetAdmittance'. */ - Template->Element1 = spGetElement(Matrix, Node1, Node1 ); - Template->Element2 = spGetElement(Matrix, Node2, Node2 ); - Template->Element3Negated = spGetElement( Matrix, Node2, Node1 ); - Template->Element4Negated = spGetElement( Matrix, Node1, Node2 ); - if ((Template->Element1 == NULL) || - (Template->Element2 == NULL) || - (Template->Element3Negated == NULL) || - (Template->Element4Negated == NULL)) - return spNO_MEMORY; - - if (Node1 == 0) - SWAP( RealNumber*, Template->Element1, Template->Element2 ); - - return spOKAY; -} -#endif /* QUAD_ELEMENT */ - - - - - - - - - -#if QUAD_ELEMENT -/* - * ADDITION OF FOUR ELEMENTS TO MATRIX BY INDEX - * - * Similar to spGetAdmittance, except that spGetAdmittance only - * handles 2-terminal components, whereas spGetQuad handles simple - * 4-terminals as well. These 4-terminals are simply generalized - * 2-terminals with the option of having the sense terminals different - * from the source and sink terminals. spGetQuad adds four - * elements to the matrix. Positive elements occur at Row1,Col1 - * Row2,Col2 while negative elements occur at Row1,Col2 and Row2,Col1. - * The routine works fine if any of the rows and columns are zero. - * This routine is only to be used after spCreate() and before - * spMNA_Preorder(), spFactor() or spOrderAndFactor() - * unless TRANSLATE is set TRUE. - * - * >>> Returns: - * Error code. - * - * >>> Arguments: - * Matrix (char *) - * Pointer to the matrix that component is to be entered in. - * Row1 (int) - * First rowstrchr for elements. Must be in the range of [0..Size] - * unless the options EXPANDABLE or TRANSLATE are used. Zero is the - * ground row. In no case may Row1 be less than zero. - * Row2 (int) - * Second rowstrchr for elements. Must be in the range of [0..Size] - * unless the options EXPANDABLE or TRANSLATE are used. Zero is the - * ground row. In no case may Row2 be less than zero. - * Col1 (int) - * First columnstrchr for elements. Must be in the range of [0..Size] - * unless the options EXPANDABLE or TRANSLATE are used. Zero is the - * ground column. In no case may Col1 be less than zero. - * Col2 (int) - * Second columnstrchr for elements. Must be in the range of [0..Size] - * unless the options EXPANDABLE or TRANSLATE are used. Zero is the - * ground column. In no case may Col2 be less than zero. - * Template (struct spTemplate *) - * Collection of pointers to four elements that are later used to directly - * address elements. User must supply the template, this routine will - * fill it. - * Real (RealNumber) - * Real data to be added to elements. - * Imag (RealNumber) - * Imag data to be added to elements. If matrix is real, this argument - * may be deleted. - * - * Possible errors: - * spNO_MEMORY - * Error is not cleared in this routine. - */ - -int -spGetQuad(MatrixPtr Matrix, int Row1, int Row2, int Col1, int Col2, - struct spTemplate *Template) -{ - /* Begin `spGetQuad'. */ - Template->Element1 = spGetElement( Matrix, Row1, Col1); - Template->Element2 = spGetElement( Matrix, Row2, Col2 ); - Template->Element3Negated = spGetElement( Matrix, Row2, Col1 ); - Template->Element4Negated = spGetElement( Matrix, Row1, Col2 ); - if ((Template->Element1 == NULL) || - (Template->Element2 == NULL) || - (Template->Element3Negated == NULL) || - (Template->Element4Negated == NULL)) - return spNO_MEMORY; - - if (Template->Element1 == & Matrix->TrashCan.Real) - SWAP( RealNumber *, Template->Element1, Template->Element2 ); - - return spOKAY; -} -#endif /* QUAD_ELEMENT */ - - - - - - - - - -#if QUAD_ELEMENT -/* - * ADDITION OF FOUR STRUCTURAL ONES TO MATRIX BY INDEX - * - * Performs similar function to spGetQuad() except this routine is - * meant for components that do not have an admittance representation. - * - * The following stamp is used: - * Pos Neg Eqn - * Pos [ . . 1 ] - * Neg [ . . -1 ] - * Eqn [ 1 -1 . ] - * - * >>> Returns: - * Error code. - * - * >>> Arguments: - * Matrix (char *) - * Pointer to the matrix that component is to be entered in. - * Pos (int) - * See stamp above. Must be in the range of [0..Size] - * unless the options EXPANDABLE or TRANSLATE are used. Zero is the - * ground row. In no case may Pos be less than zero. - * Neg (int) - * See stamp above. Must be in the range of [0..Size] - * unless the options EXPANDABLE or TRANSLATE are used. Zero is the - * ground row. In no case may Neg be less than zero. - * Eqn (int) - * See stamp above. Must be in the range of [0..Size] - * unless the options EXPANDABLE or TRANSLATE are used. Zero is the - * ground row. In no case may Eqn be less than zero. - * Template (struct spTemplate *) - * Collection of pointers to four elements that are later used to directly - * address elements. User must supply the template, this routine will - * fill it. - * - * Possible errors: - * spNO_MEMORY - * Error is not cleared in this routine. - */ - -int -spGetOnes(MatrixPtr Matrix, int Pos, int Neg, int Eqn, - struct spTemplate *Template) -{ - /* Begin `spGetOnes'. */ - Template->Element4Negated = spGetElement( Matrix, Neg, Eqn ); - Template->Element3Negated = spGetElement( Matrix, Eqn, Neg ); - Template->Element2 = spGetElement( Matrix, Pos, Eqn ); - Template->Element1 = spGetElement( Matrix, Eqn, Pos ); - if ((Template->Element1 == NULL) || - (Template->Element2 == NULL) || - (Template->Element3Negated == NULL) || - (Template->Element4Negated == NULL)) - return spNO_MEMORY; - - spADD_REAL_QUAD( *Template, 1.0 ); - return spOKAY; -} -#endif /* QUAD_ELEMENT */ - - - - - - - -/* - * - * CREATE AND SPLICE ELEMENT INTO MATRIX - * - * This routine is used to create new matrix elements and splice them into the - * matrix. - * - * >>> Returned: - * A pointer to the element that was created is returned. - * - * >>> Arguments: - * Matrix (MatrixPtr) - * Pointer to matrix. - * Row (int) - * Rowstrchr for element. - * Col (int) - * Columnstrchr for element. - * LastAddr (ElementPtr *) - * This contains the address of the pointer to the element just above the - * one being created. It is used to speed the search and it is updated with - * address of the created element. - * Fillin (int) - * Flag that indicates if created element is to be a fill-in. - * - * >>> Local variables: - * pElement (ElementPtr) - * Pointer to an element in the matrix. It is used to refer to the newly - * created element and to restring the pointers of the element's row and - * column. - * pLastElement (ElementPtr) - * Pointer to the element in the matrix that was just previously pointed - * to by pElement. It is used to restring the pointers of the element's - * row and column. - * pCreatedElement (ElementPtr) - * Pointer to the desired element, the one that was just created. - * - * >>> Possible errors: - * spNO_MEMORY - */ - -ElementPtr -spcCreateElement(MatrixPtr Matrix, int Row, int Col, - ElementPtr *LastAddr, int Fillin) -{ - ElementPtr pElement, pLastElement; - ElementPtr pCreatedElement; - - /* Begin `spcCreateElement'. */ - - if (Matrix->RowsLinked) - { - /* Row pointers cannot be ignored. */ - if (Fillin) - { - pElement = spcGetFillin( Matrix ); - Matrix->Fillins++; - } - else - { - pElement = spcGetElement( Matrix ); - Matrix->Originals++; - Matrix->NeedsOrdering = YES; - } - if (pElement == NULL) return NULL; - - /* If element is on diagonal, store pointer in Diag. */ - if (Row == Col) Matrix->Diag[Row] = pElement; - - /* Initialize Element. */ - pCreatedElement = pElement; - pElement->Row = Row; - pElement->Col = Col; - pElement->Real = 0.0; - pElement->Imag = 0.0; -#if INITIALIZE - pElement->pInitInfo = NULL; -#endif - - /* Splice element into column. */ - pElement->NextInCol = *LastAddr; - *LastAddr = pElement; - - /* Search row for proper element position. */ - pElement = Matrix->FirstInRow[Row]; - pLastElement = NULL; - while (pElement != NULL) - { - /* Search for element row position. */ - if (pElement->Col < Col) - { - /* Have not reached desired element. */ - pLastElement = pElement; - pElement = pElement->NextInRow; - } - else pElement = NULL; - } - - /* Splice element into row. */ - pElement = pCreatedElement; - if (pLastElement == NULL) - { - /* Element is first in row. */ - pElement->NextInRow = Matrix->FirstInRow[Row]; - Matrix->FirstInRow[Row] = pElement; - } - else - { - /* Element is not first in row. */ - pElement->NextInRow = pLastElement->NextInRow; - pLastElement->NextInRow = pElement; - } - - } - else - { - /* Matrix has not been factored yet. Thus get element rather - * than fill-in. Also, row pointers can be ignored. */ - - /* Allocate memory for Element. */ - pElement = spcGetElement( Matrix ); - Matrix->Originals++; - if (pElement == NULL) return NULL; - - /* If element is on diagonal, store pointer in Diag. */ - if (Row == Col) Matrix->Diag[Row] = pElement; - - /* Initialize Element. */ - pCreatedElement = pElement; - pElement->Row = Row; -#if DEBUG - pElement->Col = Col; -#endif - pElement->Real = 0.0; - pElement->Imag = 0.0; -#if INITIALIZE - pElement->pInitInfo = NULL; -#endif - - /* Splice element into column. */ - pElement->NextInCol = *LastAddr; - *LastAddr = pElement; - } - - Matrix->Elements++; - return pCreatedElement; -} - - - - - - - - -/* - * - * LINK ROWS - * - * This routine is used to generate the row links. The spGetElement() - * routines do not create row links, which are needed by the spFactor() - * routines. - * - * >>> Arguments: - * Matrix (MatrixPtr) - * Pointer to the matrix. - * - * >>> Local variables: - * pElement (ElementPtr) - * Pointer to an element in the matrix. - * FirstInRowEntry (ElementPtr *) - * A pointer into the FirstInRow array. Points to the FirstInRow entry - * currently being operated upon. - * FirstInRowArray (ArrayOfElementPtrs) - * A pointer to the FirstInRow array. Same as Matrix->FirstInRow but - * resides in a and requires less indirection so is faster to - * use. - * Col (int) - * Column currently being operated upon. - */ - -void -spcLinkRows(MatrixPtr Matrix) -{ - ElementPtr pElement, *FirstInRowEntry; - ArrayOfElementPtrs FirstInRowArray; - int Col; - - /* Begin `spcLinkRows'. */ - FirstInRowArray = Matrix->FirstInRow; - for (Col = Matrix->Size; Col >= 1; Col--) - { - /* Generate row links for the elements in the Col'th column. */ - pElement = Matrix->FirstInCol[Col]; - - while (pElement != NULL) - { - pElement->Col = Col; - FirstInRowEntry = &FirstInRowArray[pElement->Row]; - pElement->NextInRow = *FirstInRowEntry; - *FirstInRowEntry = pElement; - pElement = pElement->NextInCol; - } - } - Matrix->RowsLinked = YES; - return; -} - - - - - - - - -/* - * ENLARGE MATRIX - * - * Increases the size of the matrix. - * - * >>> Arguments: - * Matrix (MatrixPtr) - * Pointer to the matrix. - * NewSize (int) - * The new size of the matrix. - * - * >>> Local variables: - * OldAllocatedSize (int) - * The allocated size of the matrix before it is expanded. - */ - -static void -EnlargeMatrix(MatrixPtr Matrix, int NewSize) -{ - int I, OldAllocatedSize = Matrix->AllocatedSize; - - /* Begin `EnlargeMatrix'. */ - Matrix->Size = NewSize; - - if (NewSize <= OldAllocatedSize) - return; - - /* Expand the matrix frame. */ - NewSize = (int)MAX( NewSize, EXPANSION_FACTOR * OldAllocatedSize ); - Matrix->AllocatedSize = NewSize; - - if (( SP_REALLOC(Matrix->IntToExtColMap, int, NewSize+1)) == NULL) - { - Matrix->Error = spNO_MEMORY; - return; - } - if (( SP_REALLOC(Matrix->IntToExtRowMap, int, NewSize+1)) == NULL) - { - Matrix->Error = spNO_MEMORY; - return; - } - if (( SP_REALLOC(Matrix->Diag, ElementPtr, NewSize+1)) == NULL) - { - Matrix->Error = spNO_MEMORY; - return; - } - if (( SP_REALLOC(Matrix->FirstInCol, ElementPtr, NewSize+1)) == NULL) - { - Matrix->Error = spNO_MEMORY; - return; - } - if (( SP_REALLOC(Matrix->FirstInRow, ElementPtr, NewSize+1)) == NULL) - { - Matrix->Error = spNO_MEMORY; - return; - } - - /* Destroy the Markowitz and Intermediate vectors, they will be - * recreated in spOrderAndFactor(). */ - SP_FREE( Matrix->MarkowitzRow ); - SP_FREE( Matrix->MarkowitzCol ); - SP_FREE( Matrix->MarkowitzProd ); - SP_FREE( Matrix->DoRealDirect ); - SP_FREE( Matrix->DoCmplxDirect ); - SP_FREE( Matrix->Intermediate ); - Matrix->InternalVectorsAllocated = NO; - - /* Initialize the new portion of the vectors. */ - for (I = OldAllocatedSize+1; I <= NewSize; I++) - { - Matrix->IntToExtColMap[I] = I; - Matrix->IntToExtRowMap[I] = I; - Matrix->Diag[I] = NULL; - Matrix->FirstInRow[I] = NULL; - Matrix->FirstInCol[I] = NULL; - } - - return; -} - - - - - - - - -#if TRANSLATE - -/* - * EXPAND TRANSLATION ARRAYS - * - * Increases the size arrays that are used to translate external to internal - * row and column numbers. - * - * >>> Arguments: - * Matrix (MatrixPtr) - * Pointer to the matrix. - * NewSize (int) - * The new size of the translation arrays. - * - * >>> Local variables: - * OldAllocatedSize (int) - * The allocated size of the translation arrays before being expanded. - */ - -static void -ExpandTranslationArrays(MatrixPtr Matrix, int NewSize) -{ - int I, OldAllocatedSize = Matrix->AllocatedExtSize; - - /* Begin `ExpandTranslationArrays'. */ - Matrix->ExtSize = NewSize; - - if (NewSize <= OldAllocatedSize) - return; - - /* Expand the translation arrays ExtToIntRowMap and ExtToIntColMap. */ - NewSize = (int)MAX( NewSize, EXPANSION_FACTOR * OldAllocatedSize ); - Matrix->AllocatedExtSize = NewSize; - - if (( SP_REALLOC(Matrix->ExtToIntRowMap, int, NewSize+1)) == NULL) - { - Matrix->Error = spNO_MEMORY; - return; - } - if (( SP_REALLOC(Matrix->ExtToIntColMap, int, NewSize+1)) == NULL) - { - Matrix->Error = spNO_MEMORY; - return; - } - - /* Initialize the new portion of the vectors. */ - for (I = OldAllocatedSize+1; I <= NewSize; I++) - { - Matrix->ExtToIntRowMap[I] = -1; - Matrix->ExtToIntColMap[I] = -1; - } - - return; -} -#endif - - - - - - - - - -#if INITIALIZE -/* - * INITIALIZE MATRIX - * - * With the INITIALIZE compiler option (see spConfig.h) set TRUE, - * Sparse allows the user to keep initialization information with each - * structurally nonzero matrix element. Each element has a pointer - * that is set and used by the user. The user can set this pointer - * using spInstallInitInfo and may be read using spGetInitInfo. Both - * may be used only after the element exists. The function - * spInitialize() is a user customizable way to initialize the matrix. - * Passed to this routine is a function pointer. spInitialize() sweeps - * through every element in the matrix and checks the pInitInfo - * pointer (the user supplied pointer). If the pInitInfo is NULL, - * which is TRUE unless the user changes it (almost always TRUE for - * fill-ins), then the element is zeroed. Otherwise, the function - * pointer is called and passed the pInitInfo pointer as well as the - * element pointer and the external row and column numbers. If the - * user sets the value of each element, then spInitialize() replaces - * spClear(). - * - * The user function is expected to return a nonzero integer if there - * is a fatal error and zero otherwise. Upon encountering a nonzero - * return code, spInitialize() terminates and returns the error code. - * - * >>> Arguments: - * Matrix (char *) - * Pointer to matrix. - * - * >>> Possible Errors: - * Returns nonzero if error, zero otherwise. - */ - -void -spInstallInitInfo(RealNumber *pElement, void *pInitInfo) -{ - /* Begin `spInstallInitInfo'. */ - assert(pElement != NULL); - - ((ElementPtr)pElement)->pInitInfo = pInitInfo; -} - - -void * -spGetInitInfo(RealNumber *pElement) -{ - /* Begin `spGetInitInfo'. */ - assert(pElement != NULL); - - return ((ElementPtr)pElement)->pInitInfo; -} - - -int -spInitialize(MatrixPtr Matrix, int (*pInit)(RealNumber*, void *InitInfo, int , int Col)) -{ - ElementPtr pElement; - int J, Error, Col; - - /* Begin `spInitialize'. */ - assert( IS_SPARSE( Matrix ) ); - - /* Clear imaginary part of matrix if matrix is real but was complex. */ - if (Matrix->PreviousMatrixWasComplex && !Matrix->Complex) - { - for (J = Matrix->Size; J > 0; J--) - { - pElement = Matrix->FirstInCol[J]; - while (pElement != NULL) - { - pElement->Imag = 0.0; - pElement = pElement->NextInCol; - } - } - } - - /* Initialize the matrix. */ - for (J = Matrix->Size; J > 0; J--) - { - pElement = Matrix->FirstInCol[J]; - Col = Matrix->IntToExtColMap[J]; - while (pElement != NULL) - { - if (pElement->pInitInfo == NULL) - { - pElement->Real = 0.0; - pElement->Imag = 0.0; - } - else - { - Error = pInit (& pElement->Real, pElement->pInitInfo, - Matrix->IntToExtRowMap[pElement->Row], Col); - if (Error) - { - Matrix->Error = spFATAL; - return Error; - } - - } - pElement = pElement->NextInCol; - } - } - - /* Empty the trash. */ - Matrix->TrashCan.Real = 0.0; - Matrix->TrashCan.Imag = 0.0; - - Matrix->Error = spOKAY; - Matrix->Factored = NO; - Matrix->SingularCol = 0; - Matrix->SingularRow = 0; - Matrix->PreviousMatrixWasComplex = Matrix->Complex; - return 0; -} -#endif /* INITIALIZE */ diff --git a/src/maths/sparse/spconfig.h b/src/maths/sparse/spconfig.h deleted file mode 100644 index 7ded25e82..000000000 --- a/src/maths/sparse/spconfig.h +++ /dev/null @@ -1,402 +0,0 @@ -/* - * CONFIGURATION MACRO DEFINITIONS for sparse matrix routines - * - * Author: Advising professor: - * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli - * U.C. Berkeley - * - * This file contains macros for the sparse matrix routines that are used - * to define the personality of the routines. The user is expected to - * modify this file to maximize the performance of the routines with - * his/her matrices. - * - * Macros are distinguished by using solely capital letters in their - * identifiers. This contrasts with C defined identifiers which are - * strictly lower case, and program variable and procedure names which use - * both upper and lower case. - */ - - -/* - * 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. - */ - - -#ifndef ngspice_SPCONFIG_H -#define ngspice_SPCONFIG_H - - - - -#ifdef spINSIDE_SPARSE -/* - * OPTIONS - * - * These are compiler options. Set each option to one to compile that - * section of the code. If a feature is not desired, set the macro - * to NO. Recommendations are given in brackets, [ignore them]. - * - * >>> Option descriptions: - * Arithmetic Precision - * The precision of the arithmetic used by Sparse can be set by - * changing changing the spREAL macro. This macro is - * contained in the file spMatrix.h. It is strongly suggested to - * used double precision with circuit simulators. Note that - * because C always performs arithmetic operations in double - * precision, the only benefit to using single precision is that - * less storage is required. There is often a noticeable speed - * penalty when using single precision. Sparse internally refers - * to a spREAL as a RealNumber. - * EXPANDABLE - * Setting this compiler flag true (1) makes the matrix - * expandable before it has been factored. If the matrix is - * expandable, then if an element is added that would be - * considered out of bounds in the current matrix, the size of - * the matrix is increased to hold that element. As a result, - * the size of the matrix need not be known before the matrix is - * built. The matrix can be allocated with size zero and - * expanded. - * TRANSLATE - * This option allows the set of external row and column numbers - * to be non-packed. In other words, the row and column numbers - * do not have to be contiguous. The priced paid for this - * flexibility is that when TRANSLATE is set true, the time - * required to initially build the matrix will be greater because - * the external row and column number must be translated into - * internal equivalents. This translation brings about other - * benefits though. First, the spGetElement() and - * spGetAdmittance() routines may be used after the matrix has - * been factored. Further, elements, and even rows and columns, - * may be added to the matrix, and row and columns may be deleted - * from the matrix, after it has been factored. Note that when - * the set of row and column number is not a packed set, neither - * are the RHS and Solution vectors. Thus the size of these - * vectors must be at least as large as the external size, which - * is the value of the largest given row or column numbers. - * INITIALIZE - * Causes the spInitialize(), spGetInitInfo(), and - * spInstallInitInfo() routines to be compiled. These routines - * allow the user to store and read one pointer in each nonzero - * element in the matrix. spInitialize() then calls a user - * specified function for each structural nonzero in the matrix, - * and includes this pointer as well as the external row and - * column numbers as arguments. This allows the user to write - * custom matrix initialization routines. - * DIAGONAL_PIVOTING - * Many matrices, and in particular node- and modified-node - * admittance matrices, tend to be nearly symmetric and nearly - * diagonally dominant. For these matrices, it is a good idea to - * select pivots from the diagonal. With this option enabled, - * this is exactly what happens, though if no satisfactory pivot - * can be found on the diagonal, an off-diagonal pivot will be - * used. If this option is disabled, Sparse does not - * preferentially search the diagonal. Because of this, Sparse - * has a wider variety of pivot candidates available, and so - * presumably fewer fill-ins will be created. However, the - * initial pivot selection process will take considerably longer. - * If working with node admittance matrices, or other matrices - * with a strong diagonal, it is probably best to use - * DIAGONAL_PIVOTING for two reasons. First, accuracy will be - * better because pivots will be chosen from the large diagonal - * elements, thus reducing the chance of growth. Second, a near - * optimal ordering will be chosen quickly. If the class of - * matrices you are working with does not have a strong diagonal, - * do not use DIAGONAL_PIVOTING, but consider using a larger - * threshold. When DIAGONAL_PIVOTING is turned off, the following - * options and constants are not used: MODIFIED_MARKOWITZ, - * MAX_MARKOWITZ_TIES, and TIES_MULTIPLIER. - * MODIFIED_MARKOWITZ - * This specifies that the modified Markowitz method of pivot - * selection is to be used. The modified Markowitz method differs - * from standard Markowitz in two ways. First, under modified - * Markowitz, the search for a pivot can be terminated early if a - * adequate (in terms of sparsity) pivot candidate is found. - * Thus, when using modified Markowitz, the initial factorization - * can be faster, but at the expense of a suboptimal pivoting - * order that may slow subsequent factorizations. The second - * difference is in the way modified Markowitz breaks Markowitz - * ties. When two or more elements are pivot candidates and they - * all have the same Markowitz product, then the tie is broken by - * choosing the element that is best numerically. The numerically - * best element is the one with the largest ratio of its magnitude - * to the magnitude of the largest element in the same column, - * excluding itself. The modified Markowitz method results in - * marginally better accuracy. This option is most appropriate - * for use when working with very large matrices where the initial - * factor time represents an unacceptable burden. [NO] - * DELETE - * This specifies that the spDeleteRowAndCol() routine - * should be compiled. Note that for this routine to be - * compiled, both DELETE and TRANSLATE should be set true. - * STRIP - * This specifies that the spStripFills() routine should be compiled. - * MODIFIED_NODAL - * This specifies that the routine that preorders modified node - * admittance matrices should be compiled. This routine results - * in greater speed and accuracy if used with this type of - * matrix. - * QUAD_ELEMENT - * This specifies that the routines that allow four related - * elements to be entered into the matrix at once should be - * compiled. These elements are usually related to an - * admittance. The routines affected by QUAD_ELEMENT are the - * spGetAdmittance, spGetQuad and spGetOnes routines. - * TRANSPOSE - * This specifies that the routines that solve the matrix as if - * it was transposed should be compiled. These routines are - * useful when performing sensitivity analysis using the adjoint - * method. - * SCALING - * This specifies that the routine that performs scaling on the - * matrix should be complied. Scaling is not strongly - * supported. The routine to scale the matrix is provided, but - * no routines are provided to scale and descale the RHS and - * Solution vectors. It is suggested that if scaling is desired, - * it only be preformed when the pivot order is being chosen [in - * spOrderAndFactor()]. This is the only time scaling has - * an effect. The scaling may then either be removed from the - * solution by the user or the scaled factors may simply be - * thrown away. [NO] - * DOCUMENTATION - * This specifies that routines that are used to document the - * matrix, such as spPrint() and spFileMatrix(), should be - * compiled. - * DETERMINANT - * This specifies that the routine spDeterminant() should be complied. - * STABILITY - * This specifies that spLargestElement() and spRoundoff() should - * be compiled. These routines are used to check the stability (and - * hence the quality of the pivoting) of the factorization by - * computing a bound on the size of the element is the matrix E = - * A - LU. If this bound is very high after applying - * spOrderAndFactor(), then the pivot threshold should be raised. - * If the bound increases greatly after using spFactor(), then the - * matrix should probably be reordered. - * CONDITION - * This specifies that spCondition() and spNorm(), the code that - * computes a good estimate of the condition number of the matrix, - * should be compiled. - * PSEUDOCONDITION - * This specifies that spPseudoCondition(), the code that computes - * a crude and easily fooled indicator of ill-conditioning in the - * matrix, should be compiled. - * MULTIPLICATION - * This specifies that the routines to multiply the unfactored - * matrix by a vector should be compiled. - * DEBUG - * This specifies that additional error checking will be compiled. - * The type of error checked are those that are common when the - * matrix routines are first integrated into a user's program. Once - * the routines have been integrated in and are running smoothly, this - * option should be turned off. - */ - -/* Begin options. */ -#define EXPANDABLE YES -#define TRANSLATE YES -#define INITIALIZE NO -#define DIAGONAL_PIVOTING YES -#define MODIFIED_MARKOWITZ NO -#define DELETE NO -#define STRIP NO -#define MODIFIED_NODAL YES -#define QUAD_ELEMENT NO -#define TRANSPOSE YES -#define SCALING NO -#define DOCUMENTATION YES -#define MULTIPLICATION YES -#define DETERMINANT YES -#define DETERMINANT2 YES -#define STABILITY NO -#define CONDITION NO -#define PSEUDOCONDITION NO -#ifdef HAS_MINDATA -# define DEBUG NO -#else -# define DEBUG YES -#endif - -/* - * The following options affect Sparse exports and so are exported as a - * side effect. For this reason they use the `sp' prefix. The boolean - * constants YES an NO are not defined in spMatrix.h to avoid conflicts - * with user code, so use 0 for NO and 1 for YES. - */ - - - - -/* - * MATRIX CONSTANTS - * - * These constants are used throughout the sparse matrix routines. They - * should be set to suit the type of matrix being solved. Recommendations - * are given in brackets. - * - * Some terminology should be defined. The Markowitz row count is the number - * of non-zero elements in a row excluding the one being considered as pivot. - * There is one Markowitz row count for every row. The Markowitz column - * is defined similarly for columns. The Markowitz product for an element - * is the product of its row and column counts. It is a measure of how much - * work would be required on the next step of the factorization if that - * element were chosen to be pivot. A small Markowitz product is desirable. - * - * >>> Constants descriptions: - * DEFAULT_THRESHOLD - * The relative threshold used if the user enters an invalid - * threshold. Also the threshold used by spFactor() when - * calling spOrderAndFactor(). The default threshold should - * not be less than or equal to zero nor larger than one. [0.001] - * DIAG_PIVOTING_AS_DEFAULT - * This indicates whether spOrderAndFactor() should use diagonal - * pivoting as default. This issue only arises when - * spOrderAndFactor() is called from spFactor(). - * SPACE_FOR_ELEMENTS - * This number multiplied by the size of the matrix equals the number - * of elements for which memory is initially allocated in - * spCreate(). [6] - * SPACE_FOR_FILL_INS - * This number multiplied by the size of the matrix equals the number - * of elements for which memory is initially allocated and specifically - * reserved for fill-ins in spCreate(). [4] - * ELEMENTS_PER_ALLOCATION - * The number of matrix elements requested from the tmalloc utility on - * each call to it. Setting this value greater than 1 reduces the - * amount of overhead spent in this system call. On a virtual memory - * machine, its good to allocate slightly less than a page worth of - * elements at a time (or some multiple thereof). - * [For the VAX, for real only use 41, otherwise use 31] - * MINIMUM_ALLOCATED_SIZE - * The minimum allocated size of a matrix. Note that this does not - * limit the minimum size of a matrix. This just prevents having to - * resize a matrix many times if the matrix is expandable, large and - * allocated with an estimated size of zero. This number should not - * be less than one. - * EXPANSION_FACTOR - * The amount the allocated size of the matrix is increased when it - * is expanded. - * MAX_MARKOWITZ_TIES - * This number is used for two slightly different things, both of which - * relate to the search for the best pivot. First, it is the maximum - * number of elements that are Markowitz tied that will be sifted - * through when trying to find the one that is numerically the best. - * Second, it creates an upper bound on how large a Markowitz product - * can be before it eliminates the possibility of early termination - * of the pivot search. In other words, if the product of the smallest - * Markowitz product yet found and TIES_MULTIPLIER is greater than - * MAX_MARKOWITZ_TIES, then no early termination takes place. - * Set MAX_MARKOWITZ_TIES to some small value if no early termination of - * the pivot search is desired. An array of RealNumbers is allocated - * of size MAX_MARKOWITZ_TIES so it must be positive and shouldn't - * be too large. Active when MODIFIED_MARKOWITZ is 1 (true). [100] - * TIES_MULTIPLIER - * Specifies the number of Markowitz ties that are allowed to occur - * before the search for the pivot is terminated early. Set to some - * large value if no early termination of the pivot search is desired. - * This number is multiplied times the Markowitz product to determine - * how many ties are required for early termination. This means that - * more elements will be searched before early termination if a large - * number of fill-ins could be created by accepting what is currently - * considered the best choice for the pivot. Active when - * MODIFIED_MARKOWITZ is 1 (true). Setting this number to zero - * effectively eliminates all pivoting, which should be avoided. - * This number must be positive. TIES_MULTIPLIER is also used when - * diagonal pivoting breaks down. [5] - * DEFAULT_PARTITION - * Which partition mode is used by spPartition() as default. - * Possibilities include - * spDIRECT_PARTITION -- each row used direct addressing, best for - * a few relatively dense matrices. - * spINDIRECT_PARTITION -- each row used indirect addressing, best - * for a few very sparse matrices. - * spAUTO_PARTITION -- direct or indirect addressing is chosen on - * a row-by-row basis, carries a large overhead, but speeds up - * both dense and sparse matrices, best if there is a large - * number of matrices that can use the same ordering. - */ - -/* Begin constants. */ -#define DEFAULT_THRESHOLD 1.0e-3 -#define DIAG_PIVOTING_AS_DEFAULT YES -#define SPACE_FOR_ELEMENTS 6 -#define SPACE_FOR_FILL_INS 4 -#define ELEMENTS_PER_ALLOCATION 31 -#define MINIMUM_ALLOCATED_SIZE 6 -#define EXPANSION_FACTOR 1.5 -#define MAX_MARKOWITZ_TIES 100 -#define TIES_MULTIPLIER 5 -#define DEFAULT_PARTITION spAUTO_PARTITION - - - - - - -/* - * PRINTER WIDTH - * - * This macro characterize the printer for the spPrint() routine. - * - * >>> Macros: - * PRINTER_WIDTH - * The number of characters per page width. Set to 80 for terminal, - * 132 for line printer. - */ - -/* Begin printer constants. */ -#define PRINTER_WIDTH 80 - - - - - - -/* - * MACHINE CONSTANTS - * - * These numbers must be updated when the program is ported to a new machine. - */ - -/* Begin machine constants. */ - -/* - * Grab from Spice include files - */ - -#define MACHINE_RESOLUTION DBL_EPSILON -#define LARGEST_REAL DBL_MAX -#define SMALLEST_REAL DBL_MIN -#define LARGEST_SHORT_INTEGER SHRT_MAX -#define LARGEST_LONG_INTEGER LONG_MAX - - -/* - * ANNOTATION - * - * This macro changes the amount of annotation produced by the matrix - * routines. The annotation is used as a debugging aid. Change the number - * associated with ANNOTATE to change the amount of annotation produced by - * the program. - */ - -/* Begin annotation definitions. */ -#define ANNOTATE NONE - -#define NONE 0 -#define ON_STRANGE_BEHAVIOR 1 -#define FULL 2 - -#endif /* spINSIDE_SPARSE */ -#endif diff --git a/src/maths/sparse/spextra.c b/src/maths/sparse/spextra.c index 89483f391..dd7ce449e 100644 --- a/src/maths/sparse/spextra.c +++ b/src/maths/sparse/spextra.c @@ -23,10 +23,9 @@ */ #define spINSIDE_SPARSE -#include "spconfig.h" +#include "spConfig.h" #include "ngspice/spmatrix.h" -#include "spdefs.h" - +#include "spDefs.h" void spConstMult(MatrixPtr matrix, double constant)