/*
* 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
* 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
* 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.
*/
#define spINSIDE_SPARSE
#include "spConfig.h"
#include "spmatrix.h"
#include "spDefs.h"
#include "spmalloc.h"
#include "spBuild.h"
#include "spAllocate.h"
static void Translate( MatrixPtr Matrix, int *Row, int *Col );
static int EnlargeMatrix( MatrixPtr Matrix, register int NewSize );
static int ExpandTranslationArrays( MatrixPtr Matrix, register int NewSize );
/**
* 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( char *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;
}
/**
* 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)
* 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 *
spGetElement( char *eMatrix, int Row, int Col )
{
MatrixPtr Matrix = (MatrixPtr)eMatrix;
RealNumber *pElement;
ElementPtr spcFindElementInCol();
/* Begin `spGetElement'. */
ASSERT( IS_SPARSE( Matrix ) AND Row >= 0 AND Col >= 0 );
if ((Row == 0) OR (Col == 0))
{
return &Matrix->TrashCan.Real;
}
#if NOT TRANSLATE
ASSERT(Matrix->NeedsOrdering);
#endif
#if TRANSLATE
Translate( Matrix, &Row, &Col );
if (Matrix->Error == spNO_MEMORY)
{
return NULL;
}
#endif
#if NOT TRANSLATE
#if NOT EXPANDABLE
ASSERT(Row <= Matrix->Size AND Col <= Matrix->Size);
#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
/*
* 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) OR ((pElement = (RealNumber *)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 = (RealNumber*)spcFindElementInCol( Matrix,
&(Matrix->FirstInCol[Col]),
Row, Col, YES );
}
return pElement;
}
/**
* 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 (SPBOOLEAN)
* 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, register ElementPtr *LastAddr, register int Row, int Col, SPBOOLEAN CreateIfMissing )
{
register ElementPtr pElement;
ElementPtr spcCreateElement();
/* 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 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
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 NOT 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