NEURON
spbuild.c
Go to the documentation of this file.
1 #ifdef HAVE_CONFIG_H
2 #include <../../nrnconf.h>
3 #endif
4 /*
5  * MATRIX BUILD MODULE
6  *
7  * Author: Advising professor:
8  * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli
9  * UC Berkeley
10  *
11  * This file contains the routines associated with clearing, loading and
12  * preprocessing the matrix for the sparse matrix routines.
13  *
14  * >>> User accessible functions contained in this file:
15  * spClear
16  * spGetElement
17  * spGetAdmittance
18  * spGetQuad
19  * spGetOnes
20  * spInstallInitInfo
21  * spGetInitInfo
22  * spInitialize
23  *
24  * >>> Other functions contained in this file:
25  * spcFindElementInCol
26  * Translate
27  * spcCreateElement
28  * spcLinkRows
29  * EnlargeMatrix
30  * ExpandTranslationArrays
31  */
32 
33 
34 /*
35  * Revision and copyright information.
36  *
37  * Copyright (c) 1985,86,87,88
38  * by Kenneth S. Kundert and the University of California.
39  *
40  * Permission to use, copy, modify, and distribute this software and
41  * its documentation for any purpose and without fee is hereby granted,
42  * provided that the copyright notices appear in all copies and
43  * supporting documentation and that the authors and the University of
44  * California are properly credited. The authors and the University of
45  * California make no representations as to the suitability of this
46  * software for any purpose. It is provided `as is', without express
47  * or implied warranty.
48  */
49 
50 #ifndef lint
51 static char copyright[] =
52  "Sparse1.3: Copyright (c) 1985,86,87,88 by Kenneth S. Kundert";
53 static char RCSid[] =
54  "@(#)$Header$";
55 #endif
56 
57 
58 
59 
60 /*
61  * IMPORTS
62  *
63  * >>> Import descriptions:
64  * spconfig.h
65  * Macros that customize the sparse matrix routines.
66  * spmatrix.h
67  * Macros and declarations to be imported by the user.
68  * spdefs.h
69  * Matrix type and macro definitions for the sparse matrix routines.
70  */
71 
72 #define spINSIDE_SPARSE
73 #include "spconfig.h"
74 #include "spmatrix.h"
75 #include "spdefs.h"
76 
77 
78 /* avoid "declared implicitly `extern' and later `static' " warnings. */
79 
80 static void Translate();
81 static void EnlargeMatrix();
83 
84 
85 ␌
86 /*
87  * CLEAR MATRIX
88  *
89  * Sets every element of the matrix to zero and clears the error flag.
90  *
91  * >>> Arguments:
92  * Matrix <input> (char *)
93  * Pointer to matrix that is to be cleared.
94  *
95  * >>> Local variables:
96  * pElement (ElementPtr)
97  * A pointer to the element being cleared.
98  */
99 
100 void
101 spClear( eMatrix )
102 
103 char *eMatrix;
104 {
105 MatrixPtr Matrix = (MatrixPtr)eMatrix;
106 register ElementPtr pElement;
107 register int I;
108 
109 /* Begin `spClear'. */
110  ASSERT( IS_SPARSE( Matrix ) );
111 
112 /* Clear matrix. */
113 #if spCOMPLEX
115  { for (I = Matrix->Size; I > 0; I--)
116  { pElement = Matrix->FirstInCol[I];
117  while (pElement != NULL)
118  { pElement->Real = 0.0;
119  pElement->Imag = 0.0;
121  }
122  }
123  }
124  else
125 #endif
126  { for (I = Matrix->Size; I > 0; I--)
127  { pElement = Matrix->FirstInCol[I];
128  while (pElement != NULL)
129  { pElement->Real = 0.0;
131  }
132  }
133  }
134 
135 /* Empty the trash. */
136  Matrix->TrashCan.Real = 0.0;
137 #if spCOMPLEX
138  Matrix->TrashCan.Imag = 0.0;
139 #endif
140 
141  Matrix->Error = spOKAY;
142  Matrix->Factored = NO;
143  Matrix->SingularCol = 0;
144  Matrix->SingularRow = 0;
146  return;
147 }
148 
149 
150 
151 
152 
153 
154 
155 
156 
157 
158 ␌
159 /*
160  * SINGLE ELEMENT ADDITION TO MATRIX BY INDEX
161  *
162  * Finds element [Row,Col] and returns a pointer to it. If element is
163  * not found then it is created and spliced into matrix. This routine
164  * is only to be used after spCreate() and before spMNA_Preorder(),
165  * spFactor() or spOrderAndFactor(). Returns a pointer to the
166  * Real portion of a MatrixElement. This pointer is later used by
167  * spADD_xxx_ELEMENT to directly access element.
168  *
169  * >>> Returns:
170  * Returns a pointer to the element. This pointer is then used to directly
171  * access the element during successive builds.
172  *
173  * >>> Arguments:
174  * Matrix <input> (char *)
175  * Pointer to the matrix that the element is to be added to.
176  * Row <input> (int)
177  * Row index for element. Must be in the range of [0..Size] unless
178  * the options EXPANDABLE or TRANSLATE are used. Elements placed in
179  * row zero are discarded. In no case may Row be less than zero.
180  * Col <input> (int)
181  * Column index for element. Must be in the range of [0..Size] unless
182  * the options EXPANDABLE or TRANSLATE are used. Elements placed in
183  * column zero are discarded. In no case may Col be less than zero.
184  *
185  * >>> Local variables:
186  * pElement (RealNumber *)
187  * Pointer to the element.
188  *
189  * >>> Possible errors:
190  * spNO_MEMORY
191  * Error is not cleared in this routine.
192  */
193 
194 RealNumber *
195 spGetElement( eMatrix, Row, Col )
196 
197 char *eMatrix;
198 int Row, Col;
199 {
200 MatrixPtr Matrix = (MatrixPtr)eMatrix;
203 
204 /* Begin `spGetElement'. */
205  ASSERT( IS_SPARSE( Matrix ) AND Row >= 0 AND Col >= 0 );
206 
207  if ((Row == 0) OR (Col == 0))
208  return &Matrix->TrashCan.Real;
209 
210 #if NOT TRANSLATE
212 #endif
213 
214 #if TRANSLATE
215  Translate( Matrix, &Row, &Col );
216  if (Matrix->Error == spNO_MEMORY) return NULL;
217 #endif
218 
219 #if NOT TRANSLATE
220 #if NOT EXPANDABLE
221  ASSERT(Row <= Matrix->Size AND Col <= Matrix->Size);
222 #endif
223 
224 #if EXPANDABLE
225 /* Re-size Matrix if necessary. */
226  if ((Row > Matrix->Size) OR (Col > Matrix->Size))
227  EnlargeMatrix( Matrix, MAX(Row, Col) );
228  if (Matrix->Error == spNO_MEMORY) return NULL;
229 #endif
230 #endif
231 
232 /*
233  * The condition part of the following if statement tests to see if the
234  * element resides along the diagonal, if it does then it tests to see
235  * if the element has been created yet (Diag pointer not NULL). The
236  * pointer to the element is then assigned to Element after it is cast
237  * into a pointer to a RealNumber. This casting makes the pointer into
238  * a pointer to Real. This statement depends on the fact that Real
239  * is the first record in the MatrixElement structure.
240  */
241 
242  if ((Row != Col) OR ((pElement = (RealNumber *)Matrix->Diag[Row]) == NULL))
243  {
244 /*
245  * Element does not exist or does not reside along diagonal. Search
246  * column for element. As in the if statement above, the pointer to the
247  * element which is returned by spcFindElementInCol is cast into a
248  * pointer to Real, a RealNumber.
249  */
251  &(Matrix->FirstInCol[Col]),
252  Row, Col, YES );
253  }
254  return pElement;
255 }
256 
257 
258 
259 
260 
261 
262 
263 
264 
265 
266 ␌
267 /*
268  * FIND ELEMENT BY SEARCHING COLUMN
269  *
270  * Searches column starting at element specified at PtrAddr and finds element
271  * in Row. If Element does not exists, it is created. The pointer to the
272  * element is returned.
273  *
274  * >>> Returned:
275  * A pointer to the desired element:
276  *
277  * >>> Arguments:
278  * Matrix <input> (MatrixPtr)
279  * Pointer to Matrix.
280  * LastAddr <input-output> (ElementPtr *)
281  * Address of pointer that initially points to the element in Col at which
282  * the search is started. The pointer in this location may be changed if
283  * a fill-in is required in and adjacent element. For this reason it is
284  * important that LastAddr be the address of a FirstInCol or a NextInCol
285  * rather than a temporary variable.
286  * Row <input> (int)
287  * Row being searched for.
288  * Col (int)
289  * Column being searched.
290  * CreateIfMissing <input> (BOOLEAN)
291  * Indicates what to do if element is not found, create one or return a
292  * NULL pointer.
293  *
294  * Local variables:
295  * pElement (ElementPtr)
296  * Pointer used to search through matrix.
297  */
298 
300 spcFindElementInCol( Matrix, LastAddr, Row, Col, CreateIfMissing )
301 
303 register ElementPtr *LastAddr;
304 register int Row;
305 int Col;
306 BOOLEAN CreateIfMissing;
307 {
308 register ElementPtr pElement;
310 
311 /* Begin `spcFindElementInCol'. */
312  pElement = *LastAddr;
313 
314 /* Search for element. */
315  while (pElement != NULL)
316  { if (pElement->Row < Row)
317  {
318 /* Have not reached element yet. */
319  LastAddr = &(pElement->NextInCol);
321  }
322  else if (pElement->Row == Row)
323  {
324 /* Reached element. */
325  return pElement;
326  }
327  else break; /* while loop */
328  }
329 
330 /* Element does not exist and must be created. */
331  if (CreateIfMissing)
332  return spcCreateElement( Matrix, Row, Col, LastAddr, NO );
333  else return NULL;
334 }
335 
336 
337 
338 
339 
340 
341 
342 
343 #if TRANSLATE
344 ␌
345 /*
346  * TRANSLATE EXTERNAL INDICES TO INTERNAL
347  *
348  * Convert internal row and column numbers to internal row and column numbers.
349  * Also updates Ext/Int maps.
350  *
351  *
352  * >>> Arguments:
353  * Matrix <input> (MatrixPtr)
354  * Pointer to the matrix.
355  * Row <input/output> (int *)
356  * Upon entry Row is either a external row number of an external node
357  * number. Upon entry, the internal equivalent is supplied.
358  * Col <input/output> (int *)
359  * Upon entry Column is either a external column number of an external node
360  * number. Upon entry, the internal equivalent is supplied.
361  *
362  * >>> Local variables:
363  * ExtCol (int)
364  * Temporary variable used to hold the external column or node number
365  * during the external to internal column number translation.
366  * ExtRow (int)
367  * Temporary variable used to hold the external row or node number during
368  * the external to internal row number translation.
369  * IntCol (int)
370  * Temporary variable used to hold the internal column or node number
371  * during the external to internal column number translation.
372  * IntRow (int)
373  * Temporary variable used to hold the internal row or node number during
374  * the external to internal row number translation.
375  */
376 
377 static void
378 Translate( Matrix, Row, Col )
379 
381 int *Row, *Col;
382 {
383 register int IntRow, IntCol, ExtRow, ExtCol;
384 
385 /* Begin `Translate'. */
386  ExtRow = *Row;
387  ExtCol = *Col;
388 
389 /* Expand translation arrays if necessary. */
390  if ((ExtRow > Matrix->AllocatedExtSize) OR
391  (ExtCol > Matrix->AllocatedExtSize))
392  {
393  ExpandTranslationArrays( Matrix, MAX(ExtRow, ExtCol) );
394  if (Matrix->Error == spNO_MEMORY) return;
395  }
396 
397 /* Set ExtSize if necessary. */
398  if ((ExtRow > Matrix->ExtSize) OR (ExtCol > Matrix->ExtSize))
399  Matrix->ExtSize = MAX(ExtRow, ExtCol);
400 
401 /* Translate external row or node number to internal row or node number. */
402  if ((IntRow = Matrix->ExtToIntRowMap[ExtRow]) == -1)
403  { Matrix->ExtToIntRowMap[ExtRow] = ++Matrix->CurrentSize;
405  IntRow = Matrix->CurrentSize;
406 
407 #if NOT EXPANDABLE
408  ASSERT(IntRow <= Matrix->Size);
409 #endif
410 
411 #if EXPANDABLE
412 /* Re-size Matrix if necessary. */
413  if (IntRow > Matrix->Size)
414  EnlargeMatrix( Matrix, IntRow );
415  if (Matrix->Error == spNO_MEMORY) return;
416 #endif
417 
418  Matrix->IntToExtRowMap[IntRow] = ExtRow;
419  Matrix->IntToExtColMap[IntRow] = ExtRow;
420  }
421 
422 /* Translate external column or node number to internal column or node number.*/
423  if ((IntCol = Matrix->ExtToIntColMap[ExtCol]) == -1)
424  { Matrix->ExtToIntRowMap[ExtCol] = ++Matrix->CurrentSize;
426  IntCol = Matrix->CurrentSize;
427 
428 #if NOT EXPANDABLE
429  ASSERT(IntCol <= Matrix->Size);
430 #endif
431 
432 #if EXPANDABLE
433 /* Re-size Matrix if necessary. */
434  if (IntCol > Matrix->Size)
435  EnlargeMatrix( Matrix, IntCol );
436  if (Matrix->Error == spNO_MEMORY) return;
437 #endif
438 
439  Matrix->IntToExtRowMap[IntCol] = ExtCol;
440  Matrix->IntToExtColMap[IntCol] = ExtCol;
441  }
442 
443  *Row = IntRow;
444  *Col = IntCol;
445  return;
446 }
447 #endif
448 
449 
450 
451 
452 
453 ␌
454 #if QUAD_ELEMENT
455 /*
456  * ADDITION OF ADMITTANCE TO MATRIX BY INDEX
457  *
458  * Performs same function as spGetElement except rather than one
459  * element, all four Matrix elements for a floating component are
460  * added. This routine also works if component is grounded. Positive
461  * elements are placed at [Node1,Node2] and [Node2,Node1]. This
462  * routine is only to be used after spCreate() and before
463  * spMNA_Preorder(), spFactor() or spOrderAndFactor().
464  *
465  * >>> Returns:
466  * Error code.
467  *
468  * >>> Arguments:
469  * Matrix <input> (char *)
470  * Pointer to the matrix that component is to be entered in.
471  * Node1 <input> (int)
472  * Row and column indices for elements. Must be in the range of [0..Size]
473  * unless the options EXPANDABLE or TRANSLATE are used. Node zero is the
474  * ground node. In no case may Node1 be less than zero.
475  * Node2 <input> (int)
476  * Row and column indices for elements. Must be in the range of [0..Size]
477  * unless the options EXPANDABLE or TRANSLATE are used. Node zero is the
478  * ground node. In no case may Node2 be less than zero.
479  * Template <output> (struct spTemplate *)
480  * Collection of pointers to four elements that are later used to directly
481  * address elements. User must supply the template, this routine will
482  * fill it.
483  *
484  * Possible errors:
485  * spNO_MEMORY
486  * Error is not cleared in this routine.
487  */
488 
489 int
490 spGetAdmittance( Matrix, Node1, Node2, Template )
491 
492 char *Matrix;
493 int Node1, Node2;
494 struct spTemplate *Template;
495 {
496 
497 /* Begin `spGetAdmittance'. */
498  Template->Element1 = spGetElement(Matrix, Node1, Node1 );
499  Template->Element2 = spGetElement(Matrix, Node2, Node2 );
500  Template->Element3Negated = spGetElement( Matrix, Node2, Node1 );
501  Template->Element4Negated = spGetElement( Matrix, Node1, Node2 );
502  if
503  ( (Template->Element1 == NULL)
504  OR (Template->Element2 == NULL)
505  OR (Template->Element3Negated == NULL)
506  OR (Template->Element4Negated == NULL)
507  ) return spNO_MEMORY;
508 
509  if (Node1 == 0)
510  SWAP( RealNumber*, Template->Element1, Template->Element2 );
511 
512  return spOKAY;
513 }
514 #endif /* QUAD_ELEMENT */
515 
516 
517 
518 
519 
520 
521 
522 
523 ␌
524 #if QUAD_ELEMENT
525 /*
526  * ADDITION OF FOUR ELEMENTS TO MATRIX BY INDEX
527  *
528  * Similar to spGetAdmittance, except that spGetAdmittance only
529  * handles 2-terminal components, whereas spGetQuad handles simple
530  * 4-terminals as well. These 4-terminals are simply generalized
531  * 2-terminals with the option of having the sense terminals different
532  * from the source and sink terminals. spGetQuad adds four
533  * elements to the matrix. Positive elements occur at Row1,Col1
534  * Row2,Col2 while negative elements occur at Row1,Col2 and Row2,Col1.
535  * The routine works fine if any of the rows and columns are zero.
536  * This routine is only to be used after spCreate() and before
537  * spMNA_Preorder(), spFactor() or spOrderAndFactor()
538  * unless TRANSLATE is set true.
539  *
540  * >>> Returns:
541  * Error code.
542  *
543  * >>> Arguments:
544  * Matrix <input> (char *)
545  * Pointer to the matrix that component is to be entered in.
546  * Row1 <input> (int)
547  * First row index for elements. Must be in the range of [0..Size]
548  * unless the options EXPANDABLE or TRANSLATE are used. Zero is the
549  * ground row. In no case may Row1 be less than zero.
550  * Row2 <input> (int)
551  * Second row index for elements. Must be in the range of [0..Size]
552  * unless the options EXPANDABLE or TRANSLATE are used. Zero is the
553  * ground row. In no case may Row2 be less than zero.
554  * Col1 <input> (int)
555  * First column index for elements. Must be in the range of [0..Size]
556  * unless the options EXPANDABLE or TRANSLATE are used. Zero is the
557  * ground column. In no case may Col1 be less than zero.
558  * Col2 <input> (int)
559  * Second column index for elements. Must be in the range of [0..Size]
560  * unless the options EXPANDABLE or TRANSLATE are used. Zero is the
561  * ground column. In no case may Col2 be less than zero.
562  * Template <output> (struct spTemplate *)
563  * Collection of pointers to four elements that are later used to directly
564  * address elements. User must supply the template, this routine will
565  * fill it.
566  * Real <input> (RealNumber)
567  * Real data to be added to elements.
568  * Imag <input> (RealNumber)
569  * Imag data to be added to elements. If matrix is real, this argument
570  * may be deleted.
571  *
572  * Possible errors:
573  * spNO_MEMORY
574  * Error is not cleared in this routine.
575  */
576 
577 int
578 spGetQuad( Matrix, Row1, Row2, Col1, Col2, Template )
579 
580 char *Matrix;
581 int Row1, Row2, Col1, Col2;
582 struct spTemplate *Template;
583 {
584 /* Begin `spGetQuad'. */
585  Template->Element1 = spGetElement( Matrix, Row1, Col1);
586  Template->Element2 = spGetElement( Matrix, Row2, Col2 );
587  Template->Element3Negated = spGetElement( Matrix, Row2, Col1 );
588  Template->Element4Negated = spGetElement( Matrix, Row1, Col2 );
589  if
590  ( (Template->Element1 == NULL)
591  OR (Template->Element2 == NULL)
592  OR (Template->Element3Negated == NULL)
593  OR (Template->Element4Negated == NULL)
594  ) return spNO_MEMORY;
595 
596  if (Template->Element1 == &((MatrixPtr)Matrix)->TrashCan.Real)
597  SWAP( RealNumber *, Template->Element1, Template->Element2 );
598 
599  return spOKAY;
600 }
601 #endif /* QUAD_ELEMENT */
602 
603 
604 
605 
606 
607 
608 
609 
610 ␌
611 #if QUAD_ELEMENT
612 /*
613  * ADDITION OF FOUR STRUCTURAL ONES TO MATRIX BY INDEX
614  *
615  * Performs similar function to spGetQuad() except this routine is
616  * meant for components that do not have an admittance representation.
617  *
618  * The following stamp is used:
619  * Pos Neg Eqn
620  * Pos [ . . 1 ]
621  * Neg [ . . -1 ]
622  * Eqn [ 1 -1 . ]
623  *
624  * >>> Returns:
625  * Error code.
626  *
627  * >>> Arguments:
628  * Matrix <input> (char *)
629  * Pointer to the matrix that component is to be entered in.
630  * Pos <input> (int)
631  * See stamp above. Must be in the range of [0..Size]
632  * unless the options EXPANDABLE or TRANSLATE are used. Zero is the
633  * ground row. In no case may Pos be less than zero.
634  * Neg <input> (int)
635  * See stamp above. Must be in the range of [0..Size]
636  * unless the options EXPANDABLE or TRANSLATE are used. Zero is the
637  * ground row. In no case may Neg be less than zero.
638  * Eqn <input> (int)
639  * See stamp above. Must be in the range of [0..Size]
640  * unless the options EXPANDABLE or TRANSLATE are used. Zero is the
641  * ground row. In no case may Eqn be less than zero.
642  * Template <output> (struct spTemplate *)
643  * Collection of pointers to four elements that are later used to directly
644  * address elements. User must supply the template, this routine will
645  * fill it.
646  *
647  * Possible errors:
648  * spNO_MEMORY
649  * Error is not cleared in this routine.
650  */
651 
652 int
653 spGetOnes(Matrix, Pos, Neg, Eqn, Template)
654 
655 char *Matrix;
656 int Pos, Neg, Eqn;
657 struct spTemplate *Template;
658 {
659 /* Begin `spGetOnes'. */
660  Template->Element4Negated = spGetElement( Matrix, Neg, Eqn );
661  Template->Element3Negated = spGetElement( Matrix, Eqn, Neg );
662  Template->Element2 = spGetElement( Matrix, Pos, Eqn );
663  Template->Element1 = spGetElement( Matrix, Eqn, Pos );
664  if
665  ( (Template->Element1 == NULL)
666  OR (Template->Element2 == NULL)
667  OR (Template->Element3Negated == NULL)
668  OR (Template->Element4Negated == NULL)
669  ) return spNO_MEMORY;
670 
671  spADD_REAL_QUAD( *Template, 1.0 );
672  return spOKAY;
673 }
674 #endif /* QUAD_ELEMENT */
675 
676 
677 
678 
679 
680 
681 ␌
682 /*
683  *
684  * CREATE AND SPLICE ELEMENT INTO MATRIX
685  *
686  * This routine is used to create new matrix elements and splice them into the
687  * matrix.
688  *
689  * >>> Returned:
690  * A pointer to the element that was created is returned.
691  *
692  * >>> Arguments:
693  * Matrix <input> (MatrixPtr)
694  * Pointer to matrix.
695  * Row <input> (int)
696  * Row index for element.
697  * Col <input> (int)
698  * Column index for element.
699  * LastAddr <input-output> (ElementPtr *)
700  * This contains the address of the pointer to the element just above the
701  * one being created. It is used to speed the search and it is updated with
702  * address of the created element.
703  * Fillin <input> (BOOLEAN)
704  * Flag that indicates if created element is to be a fill-in.
705  *
706  * >>> Local variables:
707  * pElement (ElementPtr)
708  * Pointer to an element in the matrix. It is used to refer to the newly
709  * created element and to restring the pointers of the element's row and
710  * column.
711  * pLastElement (ElementPtr)
712  * Pointer to the element in the matrix that was just previously pointed
713  * to by pElement. It is used to restring the pointers of the element's
714  * row and column.
715  * pCreatedElement (ElementPtr)
716  * Pointer to the desired element, the one that was just created.
717  *
718  * >>> Possible errors:
719  * spNO_MEMORY
720  */
721 
723 spcCreateElement( Matrix, Row, Col, LastAddr, Fillin )
724 
726 int Row;
727 register int Col;
728 register ElementPtr *LastAddr;
729 BOOLEAN Fillin;
730 {
731 register ElementPtr pElement, pLastElement;
732 ElementPtr pCreatedElement, spcGetElement(), spcGetFillin();
733 
734 /* Begin `spcCreateElement'. */
735 
736  if (Matrix->RowsLinked)
737  {
738 /* Row pointers cannot be ignored. */
739  if (Fillin)
741  Matrix->Fillins++;
742  }
743  else
746  }
747  if (pElement == NULL) return NULL;
748 
749 /* If element is on diagonal, store pointer in Diag. */
750  if (Row == Col) Matrix->Diag[Row] = pElement;
751 
752 /* Initialize Element. */
753  pCreatedElement = pElement;
754  pElement->Row = Row;
755  pElement->Col = Col;
756  pElement->Real = 0.0;
757 #if spCOMPLEX
758  pElement->Imag = 0.0;
759 #endif
760 #if INITIALIZE
761  pElement->pInitInfo = NULL;
762 #endif
763 
764 /* Splice element into column. */
765  pElement->NextInCol = *LastAddr;
766  *LastAddr = pElement;
767 
768  /* Search row for proper element position. */
769  pElement = Matrix->FirstInRow[Row];
770  pLastElement = NULL;
771  while (pElement != NULL)
772  {
773 /* Search for element row position. */
774  if (pElement->Col < Col)
775  {
776 /* Have not reached desired element. */
777  pLastElement = pElement;
779  }
780  else pElement = NULL;
781  }
782 
783 /* Splice element into row. */
784  pElement = pCreatedElement;
785  if (pLastElement == NULL)
786  {
787 /* Element is first in row. */
789  Matrix->FirstInRow[Row] = pElement;
790  }
791  else
792 /* Element is not first in row. */
793  {
794  pElement->NextInRow = pLastElement->NextInRow;
795  pLastElement->NextInRow = pElement;
796  }
797 
798  }
799  else
800  {
801 /*
802  * Matrix has not been factored yet. Thus get element rather than fill-in.
803  * Also, row pointers can be ignored.
804  */
805 
806 /* Allocate memory for Element. */
808  if (pElement == NULL) return NULL;
809 
810 /* If element is on diagonal, store pointer in Diag. */
811  if (Row == Col) Matrix->Diag[Row] = pElement;
812 
813 /* Initialize Element. */
814  pCreatedElement = pElement;
815  pElement->Row = Row;
816 #if DEBUG
817  pElement->Col = Col;
818 #endif
819  pElement->Real = 0.0;
820 #if spCOMPLEX
821  pElement->Imag = 0.0;
822 #endif
823 #if INITIALIZE
824  pElement->pInitInfo = NULL;
825 #endif
826 
827 /* Splice element into column. */
828  pElement->NextInCol = *LastAddr;
829  *LastAddr = pElement;
830  }
831 
832  Matrix->Elements++;
833  return pCreatedElement;
834 }
835 
836 
837 
838 
839 
840 
841 
842 ␌
843 /*
844  *
845  * LINK ROWS
846  *
847  * This routine is used to generate the row links. The spGetElement()
848  * routines do not create row links, which are needed by the spFactor()
849  * routines.
850  *
851  * >>> Arguments:
852  * Matrix <input> (MatrixPtr)
853  * Pointer to the matrix.
854  *
855  * >>> Local variables:
856  * pElement (ElementPtr)
857  * Pointer to an element in the matrix.
858  * FirstInRowEntry (ElementPtr *)
859  * A pointer into the FirstInRow array. Points to the FirstInRow entry
860  * currently being operated upon.
861  * FirstInRowArray (ArrayOfElementPtrs)
862  * A pointer to the FirstInRow array. Same as Matrix->FirstInRow but
863  * resides in a register and requires less indirection so is faster to
864  * use.
865  * Col (int)
866  * Column currently being operated upon.
867  */
868 
870 
872 {
873 register ElementPtr pElement, *FirstInRowEntry;
874 register ArrayOfElementPtrs FirstInRowArray;
875 register int Col;
876 
877 /* Begin `spcLinkRows'. */
878  FirstInRowArray = Matrix->FirstInRow;
879  for (Col = Matrix->Size; Col >= 1; Col--)
880  {
881 /* Generate row links for the elements in the Col'th column. */
882  pElement = Matrix->FirstInCol[Col];
883 
884  while (pElement != NULL)
885  { pElement->Col = Col;
886  FirstInRowEntry = &FirstInRowArray[pElement->Row];
887  pElement->NextInRow = *FirstInRowEntry;
888  *FirstInRowEntry = pElement;
890  }
891  }
892  Matrix->RowsLinked = YES;
893  return;
894 }
895 
896 
897 
898 
899 
900 
901 
902 ␌
903 /*
904  * ENLARGE MATRIX
905  *
906  * Increases the size of the matrix.
907  *
908  * >>> Arguments:
909  * Matrix <input> (MatrixPtr)
910  * Pointer to the matrix.
911  * NewSize <input> (int)
912  * The new size of the matrix.
913  *
914  * >>> Local variables:
915  * OldAllocatedSize (int)
916  * The allocated size of the matrix before it is expanded.
917  */
918 
919 static
920 void EnlargeMatrix( Matrix, NewSize )
921 
923 register int NewSize;
924 {
925 register int I, OldAllocatedSize = Matrix->AllocatedSize;
926 
927 /* Begin `EnlargeMatrix'. */
928  Matrix->Size = NewSize;
929 
930  if (NewSize <= OldAllocatedSize)
931  return;
932 
933 /* Expand the matrix frame. */
934  NewSize = MAX( NewSize, EXPANSION_FACTOR * OldAllocatedSize );
935  Matrix->AllocatedSize = NewSize;
936 
937  if (( REALLOC(Matrix->IntToExtColMap, int, NewSize+1)) == NULL)
938  { Matrix->Error = spNO_MEMORY;
939  return;
940  }
941  if (( REALLOC(Matrix->IntToExtRowMap, int, NewSize+1)) == NULL)
942  { Matrix->Error = spNO_MEMORY;
943  return;
944  }
945  if (( REALLOC(Matrix->Diag, ElementPtr, NewSize+1)) == NULL)
946  { Matrix->Error = spNO_MEMORY;
947  return;
948  }
949  if (( REALLOC(Matrix->FirstInCol, ElementPtr, NewSize+1)) == NULL)
950  { Matrix->Error = spNO_MEMORY;
951  return;
952  }
953  if (( REALLOC(Matrix->FirstInRow, ElementPtr, NewSize+1)) == NULL)
954  { Matrix->Error = spNO_MEMORY;
955  return;
956  }
957 
958 /*
959  * Destroy the Markowitz and Intermediate vectors, they will be recreated
960  * in spOrderAndFactor().
961  */
969 
970 /* Initialize the new portion of the vectors. */
971  for (I = OldAllocatedSize+1; I <= NewSize; I++)
972  { Matrix->IntToExtColMap[I] = I;
973  Matrix->IntToExtRowMap[I] = I;
974  Matrix->Diag[I] = NULL;
975  Matrix->FirstInRow[I] = NULL;
976  Matrix->FirstInCol[I] = NULL;
977  }
978 
979  return;
980 }
981 
982 
983 
984 
985 
986 
987 
988 
989 #if TRANSLATE
990 ␌
991 /*
992  * EXPAND TRANSLATION ARRAYS
993  *
994  * Increases the size arrays that are used to translate external to internal
995  * row and column numbers.
996  *
997  * >>> Arguments:
998  * Matrix <input> (MatrixPtr)
999  * Pointer to the matrix.
1000  * NewSize <input> (int)
1001  * The new size of the translation arrays.
1002  *
1003  * >>> Local variables:
1004  * OldAllocatedSize (int)
1005  * The allocated size of the translation arrays before being expanded.
1006  */
1007 
1008 static
1010 
1012 register int NewSize;
1013 {
1014 register int I, OldAllocatedSize = Matrix->AllocatedExtSize;
1015 
1016 /* Begin `ExpandTranslationArrays'. */
1017  Matrix->ExtSize = NewSize;
1018 
1019  if (NewSize <= OldAllocatedSize)
1020  return;
1021 
1022 /* Expand the translation arrays ExtToIntRowMap and ExtToIntColMap. */
1023  NewSize = MAX( NewSize, EXPANSION_FACTOR * OldAllocatedSize );
1024  Matrix->AllocatedExtSize = NewSize;
1025 
1026  if (( REALLOC(Matrix->ExtToIntRowMap, int, NewSize+1)) == NULL)
1027  { Matrix->Error = spNO_MEMORY;
1028  return;
1029  }
1030  if (( REALLOC(Matrix->ExtToIntColMap, int, NewSize+1)) == NULL)
1031  { Matrix->Error = spNO_MEMORY;
1032  return;
1033  }
1034 
1035 /* Initialize the new portion of the vectors. */
1036  for (I = OldAllocatedSize+1; I <= NewSize; I++)
1037  { Matrix->ExtToIntRowMap[I] = -1;
1038  Matrix->ExtToIntColMap[I] = -1;
1039  }
1040 
1041  return;
1042 }
1043 #endif
1044 
1045 
1046 
1047 
1048 
1049 
1050 
1051 
1052 ␌
1053 #if INITIALIZE
1054 /*
1055  * INITIALIZE MATRIX
1056  *
1057  * With the INITIALIZE compiler option (see spconfig.h) set true,
1058  * Sparse allows the user to keep initialization information with each
1059  * structurally nonzero matrix element. Each element has a pointer
1060  * that is set and used by the user. The user can set this pointer
1061  * using spInstallInitInfo and may be read using spGetInitInfo. Both
1062  * may be used only after the element exists. The function
1063  * spInitialize() is a user customizable way to initialize the matrix.
1064  * Passed to this routine is a function pointer. spInitialize() sweeps
1065  * through every element in the matrix and checks the pInitInfo
1066  * pointer (the user supplied pointer). If the pInitInfo is NULL,
1067  * which is true unless the user changes it (almost always true for
1068  * fill-ins), then the element is zeroed. Otherwise, the function
1069  * pointer is called and passed the pInitInfo pointer as well as the
1070  * element pointer and the external row and column numbers. If the
1071  * user sets the value of each element, then spInitialize() replaces
1072  * spClear().
1073  *
1074  * The user function is expected to return a nonzero integer if there
1075  * is a fatal error and zero otherwise. Upon encountering a nonzero
1076  * return code, spInitialize() terminates and returns the error code.
1077  *
1078  * >>> Arguments:
1079  * Matrix <input> (char *)
1080  * Pointer to matrix.
1081  *
1082  * >>> Possible Errors:
1083  * Returns nonzero if error, zero otherwise.
1084  */
1085 
1086 void
1087 spInstallInitInfo( pElement, pInitInfo )
1088 
1090 char *pInitInfo;
1091 {
1092 /* Begin `spInstallInitInfo'. */
1093  ASSERT(pElement != NULL);
1094 
1095  ((ElementPtr)pElement)->pInitInfo = pInitInfo;
1096 }
1097 
1098 
1099 char *
1101 
1103 {
1104 /* Begin `spGetInitInfo'. */
1105  ASSERT(pElement != NULL);
1106 
1107  return (char *)((ElementPtr)pElement)->pInitInfo;
1108 }
1109 
1110 
1111 int
1112 spInitialize( eMatrix, pInit )
1113 
1114 char *eMatrix;
1115 int (*pInit)();
1116 {
1117 MatrixPtr Matrix = (MatrixPtr)eMatrix;
1118 register ElementPtr pElement;
1119 int J, Error, Col;
1120 
1121 /* Begin `spInitialize'. */
1122  ASSERT( IS_SPARSE( Matrix ) );
1123 
1124 #if spCOMPLEX
1125 /* Clear imaginary part of matrix if matrix is real but was complex. */
1127  { for (J = Matrix->Size; J > 0; J--)
1128  { pElement = Matrix->FirstInCol[J];
1129  while (pElement != NULL)
1130  { pElement->Imag = 0.0;
1132  }
1133  }
1134  }
1135 #endif /* spCOMPLEX */
1136 
1137 /* Initialize the matrix. */
1138  for (J = Matrix->Size; J > 0; J--)
1139  { pElement = Matrix->FirstInCol[J];
1140  Col = Matrix->IntToExtColMap[J];
1141  while (pElement != NULL)
1142  { if (pElement->pInitInfo == NULL)
1143  { pElement->Real = 0.0;
1144 # if spCOMPLEX
1145  pElement->Imag = 0.0;
1146 # endif
1147  }
1148  else
1149  { Error = (*pInit)((RealNumber *)pElement, pElement->pInitInfo,
1150  Matrix->IntToExtRowMap[pElement->Row], Col);
1151  if (Error)
1152  { Matrix->Error = spFATAL;
1153  return Error;
1154  }
1155 
1156  }
1158  }
1159  }
1160 
1161 /* Empty the trash. */
1162  Matrix->TrashCan.Real = 0.0;
1163 #if spCOMPLEX
1164  Matrix->TrashCan.Imag = 0.0;
1165 #endif
1166 
1167  Matrix->Error = spOKAY;
1168  Matrix->Factored = NO;
1169  Matrix->SingularCol = 0;
1170  Matrix->SingularRow = 0;
1172  return 0;
1173 }
1174 #endif /* INITIALIZE */
#define MAX(a, b)
Definition: grids.h:35
ElementPtr spcGetFillin(MatrixPtr Matrix)
Definition: spalloc.c:440
ElementPtr spcGetElement(MatrixPtr Matrix)
Definition: spalloc.c:313
static char RCSid[]
Definition: spbuild.c:53
static void Translate()
ElementPtr spcFindElementInCol(MatrixPtr Matrix, ElementPtr *LastAddr, int Row, int Col, BOOLEAN CreateIfMissing)
Definition: spbuild.c:300
void spcLinkRows(MatrixPtr Matrix)
Definition: spbuild.c:869
int spGetAdmittance(char *Matrix, int Node1, int Node2, struct spTemplate *Template)
Definition: spbuild.c:490
static void EnlargeMatrix()
void spClear(char *eMatrix)
Definition: spbuild.c:101
int spGetQuad(char *Matrix, int Row1, int Row2, int Col1, int Col2, struct spTemplate *Template)
Definition: spbuild.c:578
RealNumber * spGetElement(char *eMatrix, int Row, int Col)
Definition: spbuild.c:195
int spGetOnes(char *Matrix, int Pos, int Neg, int Eqn, struct spTemplate *Template)
Definition: spbuild.c:653
static char copyright[]
Definition: spbuild.c:51
ElementPtr spcCreateElement(MatrixPtr Matrix, int Row, int Col, ElementPtr *LastAddr, BOOLEAN Fillin)
Definition: spbuild.c:723
static void ExpandTranslationArrays()
#define FREE(ptr)
Definition: spdefs.h:446
#define OR
Definition: spdefs.h:112
#define BOOLEAN
Definition: spdefs.h:107
#define REALLOC(ptr, type, number)
Definition: spdefs.h:443
#define SWAP(type, a, b)
Definition: spdefs.h:140
struct MatrixFrame * MatrixPtr
Definition: spdefs.h:880
spREAL RealNumber
Definition: spdefs.h:468
#define YES
Definition: spdefs.h:109
#define NO
Definition: spdefs.h:108
struct MatrixElement * ElementPtr
Definition: spdefs.h:562
#define ASSERT(condition)
Definition: spdefs.h:383
#define AND
Definition: spdefs.h:111
#define NOT
Definition: spdefs.h:110
#define IS_SPARSE(matrix)
Definition: spdefs.h:120
char * spGetInitInfo()
int spInitialize()
#define spNO_MEMORY
Definition: spmatrix.h:101
#define spADD_REAL_QUAD(template, real)
Definition: spmatrix.h:200
#define spFATAL
Definition: spmatrix.h:104
void spInstallInitInfo()
#define spOKAY
Definition: spmatrix.h:97
register int Size
Definition: spoutput.c:572
register int I
Definition: spoutput.c:570
register ElementPtr pElement
Definition: spsolve.c:139
#define NULL
Definition: sptree.h:16
MatrixPtr Matrix
Definition: sputils.c:601
RealNumber Real
Definition: spdefs.h:549
struct MatrixElement * NextInCol
Definition: spdefs.h:556
struct MatrixElement * NextInRow
Definition: spdefs.h:555
int SingularCol
Definition: spdefs.h:865
int ExtSize
Definition: spdefs.h:839
int SingularRow
Definition: spdefs.h:866
int * IntToExtRowMap
Definition: spdefs.h:850
BOOLEAN * DoRealDirect
Definition: spdefs.h:836
BOOLEAN Complex
Definition: spdefs.h:832
BOOLEAN InternalVectorsAllocated
Definition: spdefs.h:848
int Fillins
Definition: spdefs.h:843
BOOLEAN PreviousMatrixWasComplex
Definition: spdefs.h:861
int AllocatedSize
Definition: spdefs.h:830
BOOLEAN * DoCmplxDirect
Definition: spdefs.h:835
ArrayOfElementPtrs FirstInCol
Definition: spdefs.h:844
int Elements
Definition: spdefs.h:837
int CurrentSize
Definition: spdefs.h:833
int AllocatedExtSize
Definition: spdefs.h:831
int * ExtToIntColMap
Definition: spdefs.h:840
BOOLEAN RowsLinked
Definition: spdefs.h:864
int * IntToExtColMap
Definition: spdefs.h:849
ArrayOfElementPtrs FirstInRow
Definition: spdefs.h:845
BOOLEAN Factored
Definition: spdefs.h:842
long * MarkowitzProd
Definition: spdefs.h:853
int Error
Definition: spdefs.h:838
BOOLEAN NeedsOrdering
Definition: spdefs.h:855
int Size
Definition: spdefs.h:868
int * ExtToIntRowMap
Definition: spdefs.h:841
int * MarkowitzRow
Definition: spdefs.h:851
ArrayOfElementPtrs Diag
Definition: spdefs.h:834
RealVector Intermediate
Definition: spdefs.h:847
int * MarkowitzCol
Definition: spdefs.h:852
struct MatrixElement TrashCan
Definition: spdefs.h:869
spREAL * Element4Negated
Definition: spmatrix.h:252
spREAL * Element1
Definition: spmatrix.h:249
spREAL * Element3Negated
Definition: spmatrix.h:251
spREAL * Element2
Definition: spmatrix.h:250