spBuild.c

Go to the documentation of this file.
00001 /*
00002  *  MATRIX BUILD MODULE
00003  *
00004  *  Author:                     Advising professor:
00005  *     Kenneth S. Kundert           Alberto Sangiovanni-Vincentelli
00006  *     UC Berkeley
00007  *
00008  *  This file contains the routines associated with clearing, loading and
00009  *  preprocessing the matrix for the sparse matrix routines.
00010  *
00011  *  >>> User accessible functions contained in this file:
00012  *  spClear
00013  *  spGetElement
00014  *  spGetAdmittance
00015  *  spGetQuad
00016  *  spGetOnes
00017  *  spInstallInitInfo
00018  *  spGetInitInfo
00019  *  spInitialize
00020  *
00021  *  >>> Other functions contained in this file:
00022  *  spcFindElementInCol
00023  *  Translate
00024  *  spcCreateElement
00025  *  spcLinkRows
00026  *  EnlargeMatrix
00027  *  ExpandTranslationArrays
00028  */
00029 
00030 
00031 /*
00032  *  Revision and copyright information.
00033  *
00034  *  Copyright (c) 1985,86,87,88
00035  *  by Kenneth S. Kundert and the University of California.
00036  *
00037  *  Permission to use, copy, modify, and distribute this software and
00038  *  its documentation for any purpose and without fee is hereby granted,
00039  *  provided that the copyright notices appear in all copies and
00040  *  supporting documentation and that the authors and the University of
00041  *  California are properly credited.  The authors and the University of
00042  *  California make no representations as to the suitability of this
00043  *  software for any purpose.  It is provided `as is', without express
00044  *  or implied warranty.
00045  */
00046 
00047 
00048 
00049 
00050 /*
00051  *  IMPORTS
00052  *
00053  *  >>> Import descriptions:
00054  *  spConfig.h
00055  *     Macros that customize the sparse matrix routines.
00056  *  spmatrix.h
00057  *     Macros and declarations to be imported by the user.
00058  *  spDefs.h
00059  *     Matrix type and macro definitions for the sparse matrix routines.
00060  */
00061 
00062 #define spINSIDE_SPARSE
00063 #include "spConfig.h"
00064 #include "spmatrix.h"
00065 #include "spDefs.h"
00066 #include "spmalloc.h"
00067 
00068 
00069 static void Translate();
00070 static EnlargeMatrix();
00071 static ExpandTranslationArrays();
00072 
00073 
00074 
00075 /*
00076  *  CLEAR MATRIX
00077  *
00078  *  Sets every element of the matrix to zero and clears the error flag.
00079  *
00080  *  >>> Arguments:
00081  *  Matrix  <input>  (char *)
00082  *     Pointer to matrix that is to be cleared.
00083  *
00084  *  >>> Local variables:
00085  *  pElement  (ElementPtr)
00086  *     A pointer to the element being cleared.
00087  */
00088 
00089 void
00090 spClear( eMatrix )
00091 
00092 char *eMatrix;
00093 {
00094 MatrixPtr  Matrix = (MatrixPtr)eMatrix;
00095 register  ElementPtr  pElement;
00096 register  int  I;
00097 
00098 /* Begin `spClear'. */
00099     ASSERT( IS_SPARSE( Matrix ) );
00100 
00101 /* Clear matrix. */
00102 #if spCOMPLEX
00103     if (Matrix->PreviousMatrixWasComplex OR Matrix->Complex)
00104     {   for (I = Matrix->Size; I > 0; I--)
00105         {   pElement = Matrix->FirstInCol[I];
00106             while (pElement != NULL)
00107             {   pElement->Real = 0.0;
00108                 pElement->Imag = 0.0;
00109                 pElement = pElement->NextInCol;
00110             }
00111         }
00112     }
00113     else
00114 #endif
00115     {   for (I = Matrix->Size; I > 0; I--)
00116         {   pElement = Matrix->FirstInCol[I];
00117             while (pElement != NULL)
00118             {   pElement->Real = 0.0;
00119                 pElement = pElement->NextInCol;
00120             }
00121         }
00122     }
00123 
00124 /* Empty the trash. */
00125     Matrix->TrashCan.Real = 0.0;
00126 #if spCOMPLEX
00127     Matrix->TrashCan.Imag = 0.0;
00128 #endif
00129 
00130     Matrix->Error = spOKAY;
00131     Matrix->Factored = NO;
00132     Matrix->SingularCol = 0;
00133     Matrix->SingularRow = 0;
00134     Matrix->PreviousMatrixWasComplex = Matrix->Complex;
00135     return;
00136 }
00137 
00138 
00139 
00140 
00141 
00142 
00143 
00144 
00145 
00146 
00147 
00148 /*
00149  *  SINGLE ELEMENT ADDITION TO MATRIX BY INDEX
00150  *
00151  *  Finds element [Row,Col] and returns a pointer to it.  If element is
00152  *  not found then it is created and spliced into matrix.  This routine
00153  *  is only to be used after spCreate() and before spMNA_Preorder(),
00154  *  spFactor() or spOrderAndFactor().  Returns a pointer to the
00155  *  Real portion of a MatrixElement.  This pointer is later used by
00156  *  spADD_xxx_ELEMENT to directly access element.
00157  *
00158  *  >>> Returns:
00159  *  Returns a pointer to the element.  This pointer is then used to directly
00160  *  access the element during successive builds.
00161  *
00162  *  >>> Arguments:
00163  *  Matrix  <input>  (char *)
00164  *     Pointer to the matrix that the element is to be added to.
00165  *  Row  <input>  (int)
00166  *     Row index for element.  Must be in the range of [0..Size] unless
00167  *     the options EXPANDABLE or TRANSLATE are used. Elements placed in
00168  *     row zero are discarded.  In no case may Row be less than zero.
00169  *  Col  <input>  (int)
00170  *     Column index for element.  Must be in the range of [0..Size] unless
00171  *     the options EXPANDABLE or TRANSLATE are used. Elements placed in
00172  *     column zero are discarded.  In no case may Col be less than zero.
00173  *
00174  *  >>> Local variables:
00175  *  pElement  (RealNumber *)
00176  *     Pointer to the element.
00177  *
00178  *  >>> Possible errors:
00179  *  spNO_MEMORY
00180  *  Error is not cleared in this routine.
00181  */
00182 
00183 RealNumber *
00184 spGetElement( eMatrix, Row, Col )
00185 
00186 char *eMatrix;
00187 int  Row, Col;
00188 {
00189 MatrixPtr  Matrix = (MatrixPtr)eMatrix;
00190 RealNumber  *pElement;
00191 ElementPtr spcFindElementInCol();
00192 
00193 
00194 /* Begin `spGetElement'. */
00195     ASSERT( IS_SPARSE( Matrix ) AND Row >= 0 AND Col >= 0 );
00196 
00197     if ((Row == 0) OR (Col == 0))
00198         return &Matrix->TrashCan.Real;
00199 
00200 #if NOT TRANSLATE
00201     ASSERT(Matrix->NeedsOrdering);
00202 #endif
00203 
00204 #if TRANSLATE
00205     Translate( Matrix, &Row, &Col );
00206     if (Matrix->Error == spNO_MEMORY) return NULL;
00207 #endif
00208 
00209 #if NOT TRANSLATE
00210 #if NOT EXPANDABLE
00211     ASSERT(Row <= Matrix->Size AND Col <= Matrix->Size);
00212 #endif
00213 
00214 #if EXPANDABLE
00215 /* Re-size Matrix if necessary. */
00216     if ((Row > Matrix->Size) OR (Col > Matrix->Size))
00217         EnlargeMatrix( Matrix, MAX(Row, Col) );
00218     if (Matrix->Error == spNO_MEMORY) return NULL;
00219 #endif
00220 #endif
00221 
00222 /*
00223  * The condition part of the following if statement tests to see if the
00224  * element resides along the diagonal, if it does then it tests to see
00225  * if the element has been created yet (Diag pointer not NULL).  The
00226  * pointer to the element is then assigned to Element after it is cast
00227  * into a pointer to a RealNumber.  This casting makes the pointer into
00228  * a pointer to Real.  This statement depends on the fact that Real
00229  * is the first record in the MatrixElement structure.
00230  */
00231 
00232     if ((Row != Col) OR ((pElement = (RealNumber *)Matrix->Diag[Row]) == NULL))
00233     {
00234 /*
00235  * Element does not exist or does not reside along diagonal.  Search
00236  * column for element.  As in the if statement above, the pointer to the
00237  * element which is returned by spcFindElementInCol is cast into a
00238  * pointer to Real, a RealNumber.
00239  */
00240         pElement = (RealNumber*)spcFindElementInCol( Matrix,
00241                                                      &(Matrix->FirstInCol[Col]),
00242                                                      Row, Col, YES );
00243     }
00244     return pElement;
00245 }
00246 
00247 
00248 
00249 
00250 
00251 
00252 
00253 
00254 
00255 
00256 
00257 /*
00258  *  FIND ELEMENT BY SEARCHING COLUMN
00259  *
00260  *  Searches column starting at element specified at PtrAddr and finds element
00261  *  in Row. If Element does not exists, it is created. The pointer to the
00262  *  element is returned.
00263  *
00264  *  >>> Returned:
00265  *  A pointer to the desired element:
00266  *
00267  *  >>> Arguments:
00268  *  Matrix  <input>  (MatrixPtr)
00269  *      Pointer to Matrix.
00270  *  LastAddr  <input-output>  (ElementPtr *)
00271  *      Address of pointer that initially points to the element in Col at which
00272  *      the search is started.  The pointer in this location may be changed if
00273  *      a fill-in is required in and adjacent element. For this reason it is
00274  *      important that LastAddr be the address of a FirstInCol or a NextInCol
00275  *      rather than a temporary variable.
00276  *  Row  <input>  (int)
00277  *      Row being searched for.
00278  *  Col  (int)
00279  *      Column being searched.
00280  *  CreateIfMissing  <input>  (SPBOOLEAN)
00281  *      Indicates what to do if element is not found, create one or return a
00282  *      NULL pointer.
00283  *
00284  *  Local variables:
00285  *  pElement  (ElementPtr)
00286  *      Pointer used to search through matrix.
00287  */
00288 
00289 ElementPtr
00290 spcFindElementInCol( Matrix, LastAddr, Row, Col, CreateIfMissing )
00291 
00292 MatrixPtr Matrix;
00293 register ElementPtr *LastAddr;
00294 register int  Row;
00295 int  Col;
00296 SPBOOLEAN  CreateIfMissing;
00297 {
00298 register  ElementPtr  pElement;
00299 ElementPtr  spcCreateElement();
00300 
00301 /* Begin `spcFindElementInCol'. */
00302     pElement = *LastAddr;
00303 
00304 /* Search for element. */
00305     while (pElement != NULL)
00306     {   if (pElement->Row < Row)
00307         {
00308 /* Have not reached element yet. */
00309             LastAddr = &(pElement->NextInCol);
00310             pElement = pElement->NextInCol;
00311         }
00312         else if (pElement->Row == Row)
00313         {
00314 /* Reached element. */
00315             return pElement;
00316         }
00317         else break;  /* while loop */
00318     }
00319 
00320 /* Element does not exist and must be created. */
00321     if (CreateIfMissing)
00322        return spcCreateElement( Matrix, Row, Col, LastAddr, NO );
00323     else return NULL;
00324 }
00325 
00326 
00327 
00328 
00329 
00330 
00331 
00332 
00333 #if TRANSLATE
00334 
00335 /*
00336  *  TRANSLATE EXTERNAL INDICES TO INTERNAL
00337  *
00338  *  Convert internal row and column numbers to internal row and column numbers.
00339  *  Also updates Ext/Int maps.
00340  *
00341  *
00342  *  >>> Arguments:
00343  *  Matrix  <input>    (MatrixPtr)
00344  *      Pointer to the matrix.
00345  *  Row  <input/output>  (int *)
00346  *     Upon entry Row is either a external row number of an external node
00347  *     number.  Upon entry, the internal equivalent is supplied.
00348  *  Col  <input/output>  (int *)
00349  *     Upon entry Column is either a external column number of an external node
00350  *     number.  Upon entry, the internal equivalent is supplied.
00351  *
00352  *  >>> Local variables:
00353  *  ExtCol  (int)
00354  *     Temporary variable used to hold the external column or node number
00355  *     during the external to internal column number translation.
00356  *  ExtRow  (int)
00357  *     Temporary variable used to hold the external row or node number during
00358  *     the external to internal row number translation.
00359  *  IntCol  (int)
00360  *     Temporary variable used to hold the internal column or node number
00361  *     during the external to internal column number translation.
00362  *  IntRow  (int)
00363  *     Temporary variable used to hold the internal row or node number during
00364  *     the external to internal row number translation.
00365  */
00366 
00367 static void
00368 Translate( Matrix, Row, Col )
00369 
00370 MatrixPtr Matrix;
00371 int  *Row, *Col;
00372 {
00373 register int IntRow, IntCol, ExtRow, ExtCol;
00374 
00375 /* Begin `Translate'. */
00376     ExtRow = *Row;
00377     ExtCol = *Col;
00378 
00379 /* Expand translation arrays if necessary. */
00380     if ((ExtRow > Matrix->AllocatedExtSize) OR
00381         (ExtCol > Matrix->AllocatedExtSize))
00382     {
00383         ExpandTranslationArrays( Matrix, MAX(ExtRow, ExtCol) );
00384         if (Matrix->Error == spNO_MEMORY) return;
00385     }
00386 
00387 /* Set ExtSize if necessary. */
00388     if ((ExtRow > Matrix->ExtSize) OR (ExtCol > Matrix->ExtSize))
00389         Matrix->ExtSize = MAX(ExtRow, ExtCol);
00390 
00391 /* Translate external row or node number to internal row or node number. */
00392     if ((IntRow = Matrix->ExtToIntRowMap[ExtRow]) == -1)
00393     {   Matrix->ExtToIntRowMap[ExtRow] = ++Matrix->CurrentSize;
00394         Matrix->ExtToIntColMap[ExtRow] = Matrix->CurrentSize;
00395         IntRow = Matrix->CurrentSize;
00396 
00397 #if NOT EXPANDABLE
00398         ASSERT(IntRow <= Matrix->Size);
00399 #endif
00400 
00401 #if EXPANDABLE
00402 /* Re-size Matrix if necessary. */
00403         if (IntRow > Matrix->Size)
00404             EnlargeMatrix( Matrix, IntRow );
00405         if (Matrix->Error == spNO_MEMORY) return;
00406 #endif
00407 
00408         Matrix->IntToExtRowMap[IntRow] = ExtRow;
00409         Matrix->IntToExtColMap[IntRow] = ExtRow;
00410     }
00411 
00412 /* Translate external column or node number to internal column or node number.*/
00413     if ((IntCol = Matrix->ExtToIntColMap[ExtCol]) == -1)
00414     {   Matrix->ExtToIntRowMap[ExtCol] = ++Matrix->CurrentSize;
00415         Matrix->ExtToIntColMap[ExtCol] = Matrix->CurrentSize;
00416         IntCol = Matrix->CurrentSize;
00417 
00418 #if NOT EXPANDABLE
00419         ASSERT(IntCol <= Matrix->Size);
00420 #endif
00421 
00422 #if EXPANDABLE
00423 /* Re-size Matrix if necessary. */
00424         if (IntCol > Matrix->Size)
00425             EnlargeMatrix( Matrix, IntCol );
00426         if (Matrix->Error == spNO_MEMORY) return;
00427 #endif
00428 
00429         Matrix->IntToExtRowMap[IntCol] = ExtCol;
00430         Matrix->IntToExtColMap[IntCol] = ExtCol;
00431     }
00432 
00433     *Row = IntRow;
00434     *Col = IntCol;
00435     return;
00436 }
00437 #endif
00438 
00439 
00440 
00441 
00442 
00443 
00444 #if QUAD_ELEMENT
00445 /*
00446  *  ADDITION OF ADMITTANCE TO MATRIX BY INDEX
00447  *
00448  *  Performs same function as spGetElement except rather than one
00449  *  element, all four Matrix elements for a floating component are
00450  *  added.  This routine also works if component is grounded.  Positive
00451  *  elements are placed at [Node1,Node2] and [Node2,Node1].  This
00452  *  routine is only to be used after spCreate() and before
00453  *  spMNA_Preorder(), spFactor() or spOrderAndFactor().
00454  *
00455  *  >>> Returns:
00456  *  Error code.
00457  *
00458  *  >>> Arguments:
00459  *  Matrix  <input>  (char *)
00460  *     Pointer to the matrix that component is to be entered in.
00461  *  Node1  <input>  (int)
00462  *     Row and column indices for elements. Must be in the range of [0..Size]
00463  *     unless the options EXPANDABLE or TRANSLATE are used. Node zero is the
00464  *     ground node.  In no case may Node1 be less than zero.
00465  *  Node2  <input>  (int)
00466  *     Row and column indices for elements. Must be in the range of [0..Size]
00467  *     unless the options EXPANDABLE or TRANSLATE are used. Node zero is the
00468  *     ground node.  In no case may Node2 be less than zero.
00469  *  Template  <output>  (struct spTemplate *)
00470  *     Collection of pointers to four elements that are later used to directly
00471  *     address elements.  User must supply the template, this routine will
00472  *     fill it.
00473  *
00474  *  Possible errors:
00475  *  spNO_MEMORY
00476  *  Error is not cleared in this routine.
00477  */
00478 
00479 int
00480 spGetAdmittance( Matrix, Node1, Node2, Template )
00481 
00482 char  *Matrix;
00483 int  Node1, Node2;
00484 struct  spTemplate  *Template;
00485 {
00486 
00487 /* Begin `spGetAdmittance'. */
00488     Template->Element1 = spGetElement(Matrix, Node1, Node1 );
00489     Template->Element2 = spGetElement(Matrix, Node2, Node2 );
00490     Template->Element3Negated = spGetElement( Matrix, Node2, Node1 );
00491     Template->Element4Negated = spGetElement( Matrix, Node1, Node2 );
00492     if
00493     (   (Template->Element1 == NULL)
00494         OR (Template->Element2 == NULL)
00495         OR (Template->Element3Negated == NULL)
00496         OR (Template->Element4Negated == NULL)
00497     )   return spNO_MEMORY;
00498 
00499     if (Node1 == 0)
00500         SWAP( RealNumber*, Template->Element1, Template->Element2 );
00501 
00502     return spOKAY;
00503 }
00504 #endif /* QUAD_ELEMENT */
00505 
00506 
00507 
00508 
00509 
00510 
00511 
00512 
00513 
00514 #if QUAD_ELEMENT
00515 /*
00516  *  ADDITION OF FOUR ELEMENTS TO MATRIX BY INDEX
00517  *
00518  *  Similar to spGetAdmittance, except that spGetAdmittance only
00519  *  handles 2-terminal components, whereas spGetQuad handles simple
00520  *  4-terminals as well.  These 4-terminals are simply generalized
00521  *  2-terminals with the option of having the sense terminals different
00522  *  from the source and sink terminals.  spGetQuad adds four
00523  *  elements to the matrix.  Positive elements occur at Row1,Col1
00524  *  Row2,Col2 while negative elements occur at Row1,Col2 and Row2,Col1.
00525  *  The routine works fine if any of the rows and columns are zero.
00526  *  This routine is only to be used after spCreate() and before
00527  *  spMNA_Preorder(), spFactor() or spOrderAndFactor()
00528  *  unless TRANSLATE is set true.
00529  *
00530  *  >>> Returns:
00531  *  Error code.
00532  *
00533  *  >>> Arguments:
00534  *  Matrix  <input>  (char *)
00535  *     Pointer to the matrix that component is to be entered in.
00536  *  Row1  <input>  (int)
00537  *     First row index for elements. Must be in the range of [0..Size]
00538  *     unless the options EXPANDABLE or TRANSLATE are used. Zero is the
00539  *     ground row.  In no case may Row1 be less than zero.
00540  *  Row2  <input>  (int)
00541  *     Second row index for elements. Must be in the range of [0..Size]
00542  *     unless the options EXPANDABLE or TRANSLATE are used. Zero is the
00543  *     ground row.  In no case may Row2 be less than zero.
00544  *  Col1  <input>  (int)
00545  *     First column index for elements. Must be in the range of [0..Size]
00546  *     unless the options EXPANDABLE or TRANSLATE are used. Zero is the
00547  *     ground column.  In no case may Col1 be less than zero.
00548  *  Col2  <input>  (int)
00549  *     Second column index for elements. Must be in the range of [0..Size]
00550  *     unless the options EXPANDABLE or TRANSLATE are used. Zero is the
00551  *     ground column.  In no case may Col2 be less than zero.
00552  *  Template  <output>  (struct spTemplate *)
00553  *     Collection of pointers to four elements that are later used to directly
00554  *     address elements.  User must supply the template, this routine will
00555  *     fill it.
00556  *  Real  <input>  (RealNumber)
00557  *     Real data to be added to elements.
00558  *  Imag  <input>  (RealNumber)
00559  *     Imag data to be added to elements.  If matrix is real, this argument
00560  *     may be deleted.
00561  *
00562  *  Possible errors:
00563  *  spNO_MEMORY
00564  *  Error is not cleared in this routine.
00565  */
00566 
00567 int
00568 spGetQuad( Matrix, Row1, Row2, Col1, Col2, Template )
00569 
00570 char  *Matrix;
00571 int  Row1, Row2, Col1, Col2;
00572 struct  spTemplate  *Template;
00573 {
00574 /* Begin `spGetQuad'. */
00575     Template->Element1 = spGetElement( Matrix, Row1, Col1);
00576     Template->Element2 = spGetElement( Matrix, Row2, Col2 );
00577     Template->Element3Negated = spGetElement( Matrix, Row2, Col1 );
00578     Template->Element4Negated = spGetElement( Matrix, Row1, Col2 );
00579     if
00580     (   (Template->Element1 == NULL)
00581         OR (Template->Element2 == NULL)
00582         OR (Template->Element3Negated == NULL)
00583         OR (Template->Element4Negated == NULL)
00584     )   return spNO_MEMORY;
00585 
00586     if (Template->Element1 == &((MatrixPtr)Matrix)->TrashCan.Real)
00587         SWAP( RealNumber *, Template->Element1, Template->Element2 );
00588 
00589     return spOKAY;
00590 }
00591 #endif /* QUAD_ELEMENT */
00592 
00593 
00594 
00595 
00596 
00597 
00598 
00599 
00600 
00601 #if QUAD_ELEMENT
00602 /*
00603  *  ADDITION OF FOUR STRUCTURAL ONES TO MATRIX BY INDEX
00604  *
00605  *  Performs similar function to spGetQuad() except this routine is
00606  *  meant for components that do not have an admittance representation.
00607  *
00608  *  The following stamp is used:
00609  *         Pos  Neg  Eqn
00610  *  Pos  [  .    .    1  ]
00611  *  Neg  [  .    .   -1  ]
00612  *  Eqn  [  1   -1    .  ]
00613  *
00614  *  >>> Returns:
00615  *  Error code.
00616  *
00617  *  >>> Arguments:
00618  *  Matrix  <input>  (char *)
00619  *     Pointer to the matrix that component is to be entered in.
00620  *  Pos  <input>  (int)
00621  *     See stamp above. Must be in the range of [0..Size]
00622  *     unless the options EXPANDABLE or TRANSLATE are used. Zero is the
00623  *     ground row.  In no case may Pos be less than zero.
00624  *  Neg  <input>  (int)
00625  *     See stamp above. Must be in the range of [0..Size]
00626  *     unless the options EXPANDABLE or TRANSLATE are used. Zero is the
00627  *     ground row.  In no case may Neg be less than zero.
00628  *  Eqn  <input>  (int)
00629  *     See stamp above. Must be in the range of [0..Size]
00630  *     unless the options EXPANDABLE or TRANSLATE are used. Zero is the
00631  *     ground row.  In no case may Eqn be less than zero.
00632  *  Template  <output>  (struct spTemplate *)
00633  *     Collection of pointers to four elements that are later used to directly
00634  *     address elements.  User must supply the template, this routine will
00635  *     fill it.
00636  *
00637  *  Possible errors:
00638  *  spNO_MEMORY
00639  *  Error is not cleared in this routine.
00640  */
00641 
00642 int
00643 spGetOnes(Matrix, Pos, Neg, Eqn, Template)
00644 
00645 char  *Matrix;
00646 int  Pos, Neg, Eqn;
00647 struct  spTemplate  *Template;
00648 {
00649 /* Begin `spGetOnes'. */
00650     Template->Element4Negated = spGetElement( Matrix, Neg, Eqn );
00651     Template->Element3Negated = spGetElement( Matrix, Eqn, Neg );
00652     Template->Element2 = spGetElement( Matrix, Pos, Eqn );
00653     Template->Element1 = spGetElement( Matrix, Eqn, Pos );
00654     if
00655     (   (Template->Element1 == NULL)
00656         OR (Template->Element2 == NULL)
00657         OR (Template->Element3Negated == NULL)
00658         OR (Template->Element4Negated == NULL)
00659     )   return spNO_MEMORY;
00660 
00661     spADD_REAL_QUAD( *Template, 1.0 );
00662     return spOKAY;
00663 }
00664 #endif /* QUAD_ELEMENT */
00665 
00666 
00667 
00668 
00669 
00670 
00671 
00672 /*
00673  *
00674  *  CREATE AND SPLICE ELEMENT INTO MATRIX
00675  *
00676  *  This routine is used to create new matrix elements and splice them into the
00677  *  matrix.
00678  *
00679  *  >>> Returned:
00680  *  A pointer to the element that was created is returned.
00681  *
00682  *  >>> Arguments:
00683  *  Matrix  <input>  (MatrixPtr)
00684  *      Pointer to matrix.
00685  *  Row  <input>  (int)
00686  *      Row index for element.
00687  *  Col  <input>  (int)
00688  *      Column index for element.
00689  *  LastAddr  <input-output>  (ElementPtr *)
00690  *      This contains the address of the pointer to the element just above the
00691  *      one being created. It is used to speed the search and it is updated with
00692  *      address of the created element.
00693  *  Fillin  <input>  (SPBOOLEAN)
00694  *      Flag that indicates if created element is to be a fill-in.
00695  *
00696  *  >>> Local variables:
00697  *  pElement  (ElementPtr)
00698  *      Pointer to an element in the matrix. It is used to refer to the newly
00699  *      created element and to restring the pointers of the element's row and
00700  *      column.
00701  *  pLastElement  (ElementPtr)
00702  *      Pointer to the element in the matrix that was just previously pointed
00703  *      to by pElement. It is used to restring the pointers of the element's
00704  *      row and column.
00705  *  pCreatedElement  (ElementPtr)
00706  *      Pointer to the desired element, the one that was just created.
00707  *
00708  *  >>> Possible errors:
00709  *  spNO_MEMORY
00710  */
00711 
00712 ElementPtr
00713 spcCreateElement( Matrix, Row, Col, LastAddr, Fillin )
00714 
00715 MatrixPtr Matrix;
00716 int  Row;
00717 register int  Col;
00718 register ElementPtr  *LastAddr;
00719 SPBOOLEAN Fillin;
00720 {
00721 register  ElementPtr  pElement, pLastElement;
00722 ElementPtr  pCreatedElement, spcGetElement(), spcGetFillin();
00723 
00724 /* Begin `spcCreateElement'. */
00725 
00726     if (Matrix->RowsLinked)
00727     {
00728 /* Row pointers cannot be ignored. */
00729         if (Fillin)
00730         {   pElement = spcGetFillin( Matrix );
00731             Matrix->Fillins++;
00732         }
00733         else
00734         {   pElement = spcGetElement( Matrix );
00735             Matrix->NeedsOrdering = YES;
00736         }
00737         if (pElement == NULL) return NULL;
00738 
00739 /* If element is on diagonal, store pointer in Diag. */
00740         if (Row == Col) Matrix->Diag[Row] = pElement;
00741 
00742 /* Initialize Element. */
00743         pCreatedElement = pElement;
00744         pElement->Row = Row;
00745         pElement->Col = Col;
00746         pElement->Real = 0.0;
00747 #if spCOMPLEX
00748         pElement->Imag = 0.0;
00749 #endif
00750 #if INITIALIZE
00751         pElement->pInitInfo = NULL;
00752 #endif
00753 
00754 /* Splice element into column. */
00755         pElement->NextInCol = *LastAddr;
00756         *LastAddr = pElement;
00757 
00758  /* Search row for proper element position. */
00759         pElement = Matrix->FirstInRow[Row];
00760         pLastElement = NULL;
00761         while (pElement != NULL)
00762         {
00763 /* Search for element row position. */
00764             if (pElement->Col < Col)
00765             {
00766 /* Have not reached desired element. */
00767                 pLastElement = pElement;
00768                 pElement = pElement->NextInRow;
00769             }
00770             else pElement = NULL;
00771         }
00772 
00773 /* Splice element into row. */
00774         pElement = pCreatedElement;
00775         if (pLastElement == NULL)
00776         {
00777 /* Element is first in row. */
00778             pElement->NextInRow = Matrix->FirstInRow[Row];
00779             Matrix->FirstInRow[Row] = pElement;
00780         }
00781         else
00782 /* Element is not first in row. */
00783         {
00784             pElement->NextInRow = pLastElement->NextInRow;
00785             pLastElement->NextInRow = pElement;
00786         }
00787 
00788     }
00789     else
00790     {
00791 /*
00792  * Matrix has not been factored yet.  Thus get element rather than fill-in.
00793  * Also, row pointers can be ignored.
00794  */
00795 
00796 /* Allocate memory for Element. */
00797         pElement = spcGetElement( Matrix );
00798         if (pElement == NULL) return NULL;
00799 
00800 /* If element is on diagonal, store pointer in Diag. */
00801         if (Row == Col) Matrix->Diag[Row] = pElement;
00802 
00803 /* Initialize Element. */
00804         pCreatedElement = pElement;
00805         pElement->Row = Row;
00806 #if DEBUG
00807         pElement->Col = Col;
00808 #endif
00809         pElement->Real = 0.0;
00810 #if spCOMPLEX
00811         pElement->Imag = 0.0;
00812 #endif
00813 #if INITIALIZE
00814         pElement->pInitInfo = NULL;
00815 #endif
00816 
00817 /* Splice element into column. */
00818         pElement->NextInCol = *LastAddr;
00819         *LastAddr = pElement;
00820     }
00821 
00822     Matrix->Elements++;
00823     return pCreatedElement;
00824 }
00825 
00826 
00827 
00828 
00829 
00830 
00831 
00832 
00833 /*
00834  *
00835  *  LINK ROWS
00836  *
00837  *  This routine is used to generate the row links.  The spGetElement()
00838  *  routines do not create row links, which are needed by the spFactor()
00839  *  routines.
00840  *
00841  *  >>>  Arguments:
00842  *  Matrix  <input>  (MatrixPtr)
00843  *      Pointer to the matrix.
00844  *
00845  *  >>> Local variables:
00846  *  pElement  (ElementPtr)
00847  *      Pointer to an element in the matrix.
00848  *  FirstInRowEntry  (ElementPtr *)
00849  *      A pointer into the FirstInRow array.  Points to the FirstInRow entry
00850  *      currently being operated upon.
00851  *  FirstInRowArray  (ArrayOfElementPtrs)
00852  *      A pointer to the FirstInRow array.  Same as Matrix->FirstInRow but
00853  *      resides in a register and requires less indirection so is faster to
00854  *      use.
00855  *  Col  (int)
00856  *      Column currently being operated upon.
00857  */
00858 
00859 spcLinkRows( Matrix )
00860 
00861 MatrixPtr Matrix;
00862 {
00863 register  ElementPtr  pElement, *FirstInRowEntry;
00864 register  ArrayOfElementPtrs  FirstInRowArray;
00865 register  int  Col;
00866 
00867 /* Begin `spcLinkRows'. */
00868     FirstInRowArray = Matrix->FirstInRow;
00869     for (Col = Matrix->Size; Col >= 1; Col--)
00870     {
00871 /* Generate row links for the elements in the Col'th column. */
00872         pElement = Matrix->FirstInCol[Col];
00873 
00874         while (pElement != NULL)
00875         {   pElement->Col = Col;
00876             FirstInRowEntry = &FirstInRowArray[pElement->Row];
00877             pElement->NextInRow = *FirstInRowEntry;
00878             *FirstInRowEntry = pElement;
00879             pElement = pElement->NextInCol;
00880         }
00881     }
00882     Matrix->RowsLinked = YES;
00883     return 0;
00884 }
00885 
00886 
00887 
00888 
00889 
00890 
00891 
00892 
00893 /*
00894  *  ENLARGE MATRIX
00895  *
00896  *  Increases the size of the matrix.
00897  *
00898  *  >>> Arguments:
00899  *  Matrix  <input>    (MatrixPtr)
00900  *      Pointer to the matrix.
00901  *  NewSize  <input>  (int)
00902  *     The new size of the matrix.
00903  *
00904  *  >>> Local variables:
00905  *  OldAllocatedSize  (int)
00906  *     The allocated size of the matrix before it is expanded.
00907  */
00908 
00909 static
00910 EnlargeMatrix( Matrix, NewSize )
00911 
00912 MatrixPtr Matrix;
00913 register int  NewSize;
00914 {
00915 register int I, OldAllocatedSize = Matrix->AllocatedSize;
00916 
00917 /* Begin `EnlargeMatrix'. */
00918     Matrix->Size = NewSize;
00919 
00920     if (NewSize <= OldAllocatedSize)
00921         return 0;
00922 
00923 /* Expand the matrix frame. */
00924     NewSize = (int) MAX( NewSize, EXPANSION_FACTOR * OldAllocatedSize );
00925     Matrix->AllocatedSize = NewSize;
00926 
00927     if (( SPREALLOC(Matrix->IntToExtColMap, int, NewSize+1)) == NULL)
00928     {   Matrix->Error = spNO_MEMORY;
00929         return 0;
00930     }
00931     if (( SPREALLOC(Matrix->IntToExtRowMap, int, NewSize+1)) == NULL)
00932     {   Matrix->Error = spNO_MEMORY;
00933         return 0;
00934     }
00935     if (( SPREALLOC(Matrix->Diag, ElementPtr, NewSize+1)) == NULL)
00936     {   Matrix->Error = spNO_MEMORY;
00937         return 0;
00938     }
00939     if (( SPREALLOC(Matrix->FirstInCol, ElementPtr, NewSize+1)) == NULL)
00940     {   Matrix->Error = spNO_MEMORY;
00941         return 0;
00942     }
00943     if (( SPREALLOC(Matrix->FirstInRow, ElementPtr, NewSize+1)) == NULL)
00944     {   Matrix->Error = spNO_MEMORY;
00945         return 0;
00946     }
00947 
00948 /*
00949  * Destroy the Markowitz and Intermediate vectors, they will be recreated
00950  * in spOrderAndFactor().
00951  */
00952     SPFREE( Matrix->MarkowitzRow );
00953     SPFREE( Matrix->MarkowitzCol );
00954     SPFREE( Matrix->MarkowitzProd );
00955     SPFREE( Matrix->DoRealDirect );
00956     SPFREE( Matrix->DoCmplxDirect );
00957     SPFREE( Matrix->Intermediate );
00958     Matrix->InternalVectorsAllocated = NO;
00959 
00960 /* Initialize the new portion of the vectors. */
00961     for (I = OldAllocatedSize+1; I <= NewSize; I++)
00962     {   Matrix->IntToExtColMap[I] = I;
00963         Matrix->IntToExtRowMap[I] = I;
00964         Matrix->Diag[I] = NULL;
00965         Matrix->FirstInRow[I] = NULL;
00966         Matrix->FirstInCol[I] = NULL;
00967     }
00968 
00969     return 0;
00970 }
00971 
00972 
00973 
00974 
00975 
00976 
00977 
00978 
00979 #if TRANSLATE
00980 
00981 /*
00982  *  EXPAND TRANSLATION ARRAYS
00983  *
00984  *  Increases the size arrays that are used to translate external to internal
00985  *  row and column numbers.
00986  *
00987  *  >>> Arguments:
00988  *  Matrix  <input>    (MatrixPtr)
00989  *      Pointer to the matrix.
00990  *  NewSize  <input>  (int)
00991  *     The new size of the translation arrays.
00992  *
00993  *  >>> Local variables:
00994  *  OldAllocatedSize  (int)
00995  *     The allocated size of the translation arrays before being expanded.
00996  */
00997 
00998 static
00999 ExpandTranslationArrays( Matrix, NewSize )
01000 
01001 MatrixPtr Matrix;
01002 register int  NewSize;
01003 {
01004 register int I, OldAllocatedSize = Matrix->AllocatedExtSize;
01005 
01006 /* Begin `ExpandTranslationArrays'. */
01007     Matrix->ExtSize = NewSize;
01008 
01009     if (NewSize <= OldAllocatedSize)
01010         return 0;
01011 
01012 /* Expand the translation arrays ExtToIntRowMap and ExtToIntColMap. */
01013     NewSize = (int) MAX( NewSize, EXPANSION_FACTOR * OldAllocatedSize );
01014     Matrix->AllocatedExtSize = NewSize;
01015 
01016     if (( SPREALLOC(Matrix->ExtToIntRowMap, int, NewSize+1)) == NULL)
01017     {   Matrix->Error = spNO_MEMORY;
01018         return 0;
01019     }
01020     if (( SPREALLOC(Matrix->ExtToIntColMap, int, NewSize+1)) == NULL)
01021     {   Matrix->Error = spNO_MEMORY;
01022         return 0;
01023     }
01024 
01025 /* Initialize the new portion of the vectors. */
01026     for (I = OldAllocatedSize+1; I <= NewSize; I++)
01027     {   Matrix->ExtToIntRowMap[I] = -1;
01028         Matrix->ExtToIntColMap[I] = -1;
01029     }
01030 
01031     return 0;
01032 }
01033 #endif
01034 
01035 
01036 
01037 
01038 
01039 
01040 
01041 
01042 
01043 #if INITIALIZE
01044 /*
01045  *   INITIALIZE MATRIX
01046  *
01047  *   With the INITIALIZE compiler option (see spConfig.h) set true,
01048  *   Sparse allows the user to keep initialization information with each
01049  *   structurally nonzero matrix element.  Each element has a pointer
01050  *   that is set and used by the user.  The user can set this pointer
01051  *   using spInstallInitInfo and may be read using spGetInitInfo.  Both
01052  *   may be used only after the element exists.  The function
01053  *   spInitialize() is a user customizable way to initialize the matrix.
01054  *   Passed to this routine is a function pointer.  spInitialize() sweeps
01055  *   through every element in the matrix and checks the pInitInfo
01056  *   pointer (the user supplied pointer).  If the pInitInfo is NULL,
01057  *   which is true unless the user changes it (almost always true for
01058  *   fill-ins), then the element is zeroed.  Otherwise, the function
01059  *   pointer is called and passed the pInitInfo pointer as well as the
01060  *   element pointer and the external row and column numbers.  If the
01061  *   user sets the value of each element, then spInitialize() replaces
01062  *   spClear().
01063  *
01064  *   The user function is expected to return a nonzero integer if there
01065  *   is a fatal error and zero otherwise.  Upon encountering a nonzero
01066  *   return code, spInitialize() terminates and returns the error code.
01067  *
01068  *   >>> Arguments:
01069  *   Matrix  <input>  (char *)
01070  *       Pointer to matrix.
01071  *
01072  *   >>> Possible Errors:
01073  *   Returns nonzero if error, zero otherwise.
01074  */
01075 
01076 void
01077 spInstallInitInfo( pElement, pInitInfo )
01078 
01079 RealNumber *pElement;
01080 char *pInitInfo;
01081 {
01082 /* Begin `spInstallInitInfo'. */
01083     ASSERT(pElement != NULL);
01084 
01085     ((ElementPtr)pElement)->pInitInfo = pInitInfo;
01086 }
01087 
01088 
01089 char *
01090 spGetInitInfo( pElement )
01091 
01092 RealNumber *pElement;
01093 {
01094 /* Begin `spGetInitInfo'. */
01095     ASSERT(pElement != NULL);
01096 
01097     return (char *)((ElementPtr)pElement)->pInitInfo;
01098 }
01099 
01100 
01101 int
01102 spInitialize( eMatrix, pInit )
01103 
01104 char *eMatrix;
01105 int (*pInit)();
01106 {
01107 MatrixPtr Matrix = (MatrixPtr)eMatrix;
01108 register ElementPtr pElement;
01109 int J, Error, Col;
01110 
01111 /* Begin `spInitialize'. */
01112     ASSERT( IS_SPARSE( Matrix ) );
01113 
01114 #if spCOMPLEX
01115 /* Clear imaginary part of matrix if matrix is real but was complex. */
01116     if (Matrix->PreviousMatrixWasComplex AND NOT Matrix->Complex)
01117     {   for (J = Matrix->Size; J > 0; J--)
01118         {   pElement = Matrix->FirstInCol[J];
01119             while (pElement != NULL)
01120             {   pElement->Imag = 0.0;
01121                 pElement = pElement->NextInCol;
01122             }
01123         }
01124     }
01125 #endif /* spCOMPLEX */
01126 
01127 /* Initialize the matrix. */
01128     for (J = Matrix->Size; J > 0; J--)
01129     {   pElement = Matrix->FirstInCol[J];
01130         Col = Matrix->IntToExtColMap[J];
01131         while (pElement != NULL)
01132         {   if (pElement->pInitInfo == NULL)
01133             {   pElement->Real = 0.0;
01134 #               if spCOMPLEX
01135                     pElement->Imag = 0.0;
01136 #               endif
01137             }
01138             else
01139             {   Error = (*pInit)((RealNumber *)pElement, pElement->pInitInfo,
01140                                  Matrix->IntToExtRowMap[pElement->Row], Col);
01141                 if (Error)
01142                 {   Matrix->Error = spFATAL;
01143                     return Error;
01144                 }
01145 
01146             }
01147             pElement = pElement->NextInCol;
01148         }
01149     }
01150 
01151 /* Empty the trash. */
01152     Matrix->TrashCan.Real = 0.0;
01153 #if spCOMPLEX
01154     Matrix->TrashCan.Imag = 0.0;
01155 #endif
01156 
01157     Matrix->Error = spOKAY;
01158     Matrix->Factored = NO;
01159     Matrix->SingularCol = 0;
01160     Matrix->SingularRow = 0;
01161     Matrix->PreviousMatrixWasComplex = Matrix->Complex;
01162     return 0;
01163 }
01164 #endif /* INITIALIZE */

Generated on Sun Mar 4 15:04:00 2007 for Scilab [trunk] by  doxygen 1.5.1