NEURON
sputils.c
Go to the documentation of this file.
1 #ifdef HAVE_CONFIG_H
2 #include <../../nrnconf.h>
3 #endif
4 /*
5  * MATRIX UTILITY MODULE
6  *
7  * Author: Advising professor:
8  * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli
9  * UC Berkeley
10  *
11  * This file contains various optional utility routines.
12  *
13  * >>> User accessible functions contained in this file:
14  * spMNA_Preorder
15  * spScale
16  * spMultiply
17  * spMultTransposed
18  * spDeterminant
19  * spStrip
20  * spDeleteRowAndCol
21  * spPseudoCondition
22  * spCondition
23  * spNorm
24  * spLargestElement
25  * spRoundoff
26  *
27  * >>> Other functions contained in this file:
28  * CountTwins
29  * SwapCols
30  * ScaleComplexMatrix
31  * ComplexMatrixMultiply
32  * ComplexCondition
33  */
34 
35 
36 /*
37  * Revision and copyright information.
38  *
39  * Copyright (c) 1985,86,87,88
40  * by Kenneth S. Kundert and the University of California.
41  *
42  * Permission to use, copy, modify, and distribute this software and
43  * its documentation for any purpose and without fee is hereby granted,
44  * provided that the copyright notices appear in all copies and
45  * supporting documentation and that the authors and the University of
46  * California are properly credited. The authors and the University of
47  * California make no representations as to the suitability of this
48  * software for any purpose. It is provided `as is', without express
49  * or implied warranty.
50  */
51 
52 #ifndef lint
53 static char copyright[] =
54  "Sparse1.3: Copyright (c) 1985,86,87,88 by Kenneth S. Kundert";
55 static char RCSid[] =
56  "@(#)$Header$";
57 #endif
58 
59 
60 
61 /*
62  * IMPORTS
63  *
64  * >>> Import descriptions:
65  * spconfig.h
66  * Macros that customize the sparse matrix routines.
67  * spmatrix.h
68  * Macros and declarations to be imported by the user.
69  * spdefs.h
70  * Matrix type and macro definitions for the sparse matrix routines.
71  */
72 
73 #define spINSIDE_SPARSE
74 #include "spconfig.h"
75 #include "spmatrix.h"
76 #include "spdefs.h"
77 
78 extern void spcLinkRows(MatrixPtr);
79 extern void spcRowExchange(MatrixPtr, int row1, int row2);
80 extern void spcColExchange(MatrixPtr, int col1, int col2);
81 
82 /* avoid "declared implicitly `extern' and later `static' " warnings. */
83 static int CountTwins();
84 static void SwapCols();
85 static void ScaleComplexMatrix();
86 static void ComplexMatrixMultiply();
89 
90 
91 
92 
93 #if MODIFIED_NODAL
94 /*
95  * PREORDER MODIFIED NODE ADMITTANCE MATRIX TO REMOVE ZEROS FROM DIAGONAL
96  *
97  * This routine massages modified node admittance matrices to remove
98  * zeros from the diagonal. It takes advantage of the fact that the
99  * row and column associated with a zero diagonal usually have
100  * structural ones placed symmetricly. This routine should be used
101  * only on modified node admittance matrices and should be executed
102  * after the matrix has been built but before the factorization
103  * begins. It should be executed for the initial factorization only
104  * and should be executed before the rows have been linked. Thus it
105  * should be run before using spScale(), spMultiply(),
106  * spDeleteRowAndCol(), or spNorm().
107  *
108  * This routine exploits the fact that the structural ones are placed
109  * in the matrix in symmetric twins. For example, the stamps for
110  * grounded and a floating voltage sources are
111  * grounded: floating:
112  * [ x x 1 ] [ x x 1 ]
113  * [ x x ] [ x x -1 ]
114  * [ 1 ] [ 1 -1 ]
115  * Notice for the grounded source, there is one set of twins, and for
116  * the floating, there are two sets. We remove the zero from the diagonal
117  * by swapping the rows associated with a set of twins. For example:
118  * grounded: floating 1: floating 2:
119  * [ 1 ] [ 1 -1 ] [ x x 1 ]
120  * [ x x ] [ x x -1 ] [ 1 -1 ]
121  * [ x x 1 ] [ x x 1 ] [ x x -1 ]
122  *
123  * It is important to deal with any zero diagonals that only have one
124  * set of twins before dealing with those that have more than one because
125  * swapping row destroys the symmetry of any twins in the rows being
126  * swapped, which may limit future moves. Consider
127  * [ x x 1 ]
128  * [ x x -1 1 ]
129  * [ 1 -1 ]
130  * [ 1 ]
131  * There is one set of twins for diagonal 4 and two for diagonal 3.
132  * Dealing with diagonal 4 first requires swapping rows 2 and 4.
133  * [ x x 1 ]
134  * [ 1 ]
135  * [ 1 -1 ]
136  * [ x x -1 1 ]
137  * We can now deal with diagonal 3 by swapping rows 1 and 3.
138  * [ 1 -1 ]
139  * [ 1 ]
140  * [ x x 1 ]
141  * [ x x -1 1 ]
142  * And we are done, there are no zeros left on the diagonal. However, if
143  * we originally dealt with diagonal 3 first, we could swap rows 2 and 3
144  * [ x x 1 ]
145  * [ 1 -1 ]
146  * [ x x -1 1 ]
147  * [ 1 ]
148  * Diagonal 4 no longer has a symmetric twin and we cannot continue.
149  *
150  * So we always take care of lone twins first. When none remain, we
151  * choose arbitrarily a set of twins for a diagonal with more than one set
152  * and swap the rows corresponding to that twin. We then deal with any
153  * lone twins that were created and repeat the procedure until no
154  * zero diagonals with symmetric twins remain.
155  *
156  * In this particular implementation, columns are swapped rather than rows.
157  * The algorithm used in this function was developed by Ken Kundert and
158  * Tom Quarles.
159  *
160  * >>> Arguments:
161  * eMatrix <input> (char *)
162  * Pointer to the matrix to be preordered.
163  *
164  * >>> Local variables;
165  * J (int)
166  * Column with zero diagonal being currently considered.
167  * pTwin1 (ElementPtr)
168  * Pointer to the twin found in the column belonging to the zero diagonal.
169  * pTwin2 (ElementPtr)
170  * Pointer to the twin found in the row belonging to the zero diagonal.
171  * belonging to the zero diagonal.
172  * AnotherPassNeeded (BOOLEAN)
173  * Flag indicating that at least one zero diagonal with symmetric twins
174  * remain.
175  * StartAt (int)
176  * Column number of first zero diagonal with symmetric twins.
177  * Swapped (BOOLEAN)
178  * Flag indicating that columns were swapped on this pass.
179  * Twins (int)
180  * Number of symmetric twins corresponding to current zero diagonal.
181  */
182 
183 void
184 spMNA_Preorder( eMatrix )
185 
186 char *eMatrix;
187 {
188 MatrixPtr Matrix = (MatrixPtr)eMatrix;
189 register int J, Size;
190 ElementPtr pTwin1=0, pTwin2=0;
191 int Twins, StartAt = 1;
192 BOOLEAN Swapped, AnotherPassNeeded;
193 
194 /* Begin `spMNA_Preorder'. */
195  ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored );
196 
197  if (Matrix->RowsLinked) return;
198  Size = Matrix->Size;
199  Matrix->Reordered = YES;
200 
201  do
202  { AnotherPassNeeded = Swapped = NO;
203 
204 /* Search for zero diagonals with lone twins. */
205  for (J = StartAt; J <= Size; J++)
206  { if (Matrix->Diag[J] == NULL)
207  { Twins = CountTwins( Matrix, J, &pTwin1, &pTwin2 );
208  if (Twins == 1)
209  { /* Lone twins found, swap rows. */
210  SwapCols( Matrix, pTwin1, pTwin2 );
211  Swapped = YES;
212  }
213  else if ((Twins > 1) AND NOT AnotherPassNeeded)
214  { AnotherPassNeeded = YES;
215  StartAt = J;
216  }
217  }
218  }
219 
220 /* All lone twins are gone, look for zero diagonals with multiple twins. */
221  if (AnotherPassNeeded)
222  { for (J = StartAt; NOT Swapped AND (J <= Size); J++)
223  { if (Matrix->Diag[J] == NULL)
224  { Twins = CountTwins( Matrix, J, &pTwin1, &pTwin2 );
225  SwapCols( Matrix, pTwin1, pTwin2 );
226  Swapped = YES;
227  }
228  }
229  }
230  } while (AnotherPassNeeded);
231  return;
232 }
233 
234 
235 
236 
237 /*
238  * COUNT TWINS
239  *
240  * This function counts the number of symmetric twins associated with
241  * a zero diagonal and returns one set of twins if any exist. The
242  * count is terminated early at two.
243  */
244 
245 static int
246 CountTwins( Matrix, Col, ppTwin1, ppTwin2 )
247 
249 int Col;
250 ElementPtr *ppTwin1, *ppTwin2;
251 {
252 int Row, Twins = 0;
253 ElementPtr pTwin1, pTwin2;
254 
255 /* Begin `CountTwins'. */
256 
257  pTwin1 = Matrix->FirstInCol[Col];
258  while (pTwin1 != NULL)
259  { if (ABS(pTwin1->Real) == 1.0)
260  { Row = pTwin1->Row;
261  pTwin2 = Matrix->FirstInCol[Row];
262  while ((pTwin2 != NULL) AND (pTwin2->Row != Col))
263  pTwin2 = pTwin2->NextInCol;
264  if ((pTwin2 != NULL) AND (ABS(pTwin2->Real) == 1.0))
265  { /* Found symmetric twins. */
266  if (++Twins >= 2) return Twins;
267  (*ppTwin1 = pTwin1)->Col = Col;
268  (*ppTwin2 = pTwin2)->Col = Row;
269  }
270  }
271  pTwin1 = pTwin1->NextInCol;
272  }
273  return Twins;
274 }
275 
276 
277 
278 
279 /*
280  * SWAP COLUMNS
281  *
282  * This function swaps two columns and is applicable before the rows are
283  * linked.
284  */
285 
286 static
287 void SwapCols( Matrix, pTwin1, pTwin2 )
288 
290 ElementPtr pTwin1, pTwin2;
291 {
292 int Col1 = pTwin1->Col, Col2 = pTwin2->Col;
293 
294 /* Begin `SwapCols'. */
295 
296  SWAP (ElementPtr, Matrix->FirstInCol[Col1], Matrix->FirstInCol[Col2]);
297  SWAP (int, Matrix->IntToExtColMap[Col1], Matrix->IntToExtColMap[Col2]);
298 #if TRANSLATE
299  Matrix->ExtToIntColMap[Matrix->IntToExtColMap[Col2]]=Col2;
300  Matrix->ExtToIntColMap[Matrix->IntToExtColMap[Col1]]=Col1;
301 #endif
302 
303  Matrix->Diag[Col1] = pTwin2;
304  Matrix->Diag[Col2] = pTwin1;
306  return;
307 }
308 #endif /* MODIFIED_NODAL */
309 
310 
311 
312 
313 
314 
315 
316 
317 
318 #if SCALING
319 /*
320  * SCALE MATRIX
321  *
322  * This function scales the matrix to enhance the possibility of
323  * finding a good pivoting order. Note that scaling enhances accuracy
324  * of the solution only if it affects the pivoting order, so it makes
325  * no sense to scale the matrix before spFactor(). If scaling is
326  * desired it should be done before spOrderAndFactor(). There
327  * are several things to take into account when choosing the scale
328  * factors. First, the scale factors are directly multiplied against
329  * the elements in the matrix. To prevent roundoff, each scale factor
330  * should be equal to an integer power of the number base of the
331  * machine. Since most machines operate in base two, scale factors
332  * should be a power of two. Second, the matrix should be scaled such
333  * that the matrix of element uncertainties is equilibrated. Third,
334  * this function multiplies the scale factors by the elements, so if
335  * one row tends to have uncertainties 1000 times smaller than the
336  * other rows, then its scale factor should be 1024, not 1/1024.
337  * Fourth, to save time, this function does not scale rows or columns
338  * if their scale factors are equal to one. Thus, the scale factors
339  * should be normalized to the most common scale factor. Rows and
340  * columns should be normalized separately. For example, if the size
341  * of the matrix is 100 and 10 rows tend to have uncertainties near
342  * 1e-6 and the remaining 90 have uncertainties near 1e-12, then the
343  * scale factor for the 10 should be 1/1,048,576 and the scale factors
344  * for the remaining 90 should be 1. Fifth, since this routine
345  * directly operates on the matrix, it is necessary to apply the scale
346  * factors to the RHS and Solution vectors. It may be easier to
347  * simply use spOrderAndFactor() on a scaled matrix to choose the
348  * pivoting order, and then throw away the matrix. Subsequent
349  * factorizations, performed with spFactor(), will not need to have
350  * the RHS and Solution vectors descaled. Lastly, this function
351  * should not be executed before the function spMNA_Preorder.
352  *
353  * >>> Arguments:
354  * eMatrix <input> (char *)
355  * Pointer to the matrix to be scaled.
356  * SolutionScaleFactors <input> (RealVector)
357  * The array of Solution scale factors. These factors scale the columns.
358  * All scale factors are real valued.
359  * RHS_ScaleFactors <input> (RealVector)
360  * The array of RHS scale factors. These factors scale the rows.
361  * All scale factors are real valued.
362  *
363  * >>> Local variables:
364  * lSize (int)
365  * Local version of the size of the matrix.
366  * pElement (ElementPtr)
367  * Pointer to an element in the matrix.
368  * pExtOrder (int *)
369  * Pointer into either IntToExtRowMap or IntToExtColMap vector. Used to
370  * compensate for any row or column swaps that have been performed.
371  * ScaleFactor (RealNumber)
372  * The scale factor being used on the current row or column.
373  */
374 
375 void
376 spScale( eMatrix, RHS_ScaleFactors, SolutionScaleFactors )
377 
378 char *eMatrix;
379 register RealVector RHS_ScaleFactors, SolutionScaleFactors;
380 {
381 MatrixPtr Matrix = (MatrixPtr)eMatrix;
382 register ElementPtr pElement;
383 register int I, lSize, *pExtOrder;
384 RealNumber ScaleFactor;
385 
386 /* Begin `spScale'. */
387  ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored );
388  if (NOT Matrix->RowsLinked) spcLinkRows( Matrix );
389 
390 #if spCOMPLEX
391  if (Matrix->Complex)
392  { ScaleComplexMatrix( Matrix, RHS_ScaleFactors, SolutionScaleFactors );
393  return;
394  }
395 #endif
396 
397 #if REAL
398  lSize = Matrix->Size;
399 
400 /* Correct pointers to arrays for ARRAY_OFFSET */
401 #if NOT ARRAY_OFFSET
402  --RHS_ScaleFactors;
403  --SolutionScaleFactors;
404 #endif
405 
406 /* Scale Rows */
407  pExtOrder = &Matrix->IntToExtRowMap[1];
408  for (I = 1; I <= lSize; I++)
409  { if ((ScaleFactor = RHS_ScaleFactors[*(pExtOrder++)]) != 1.0)
410  { pElement = Matrix->FirstInRow[I];
411 
412  while (pElement != NULL)
413  { pElement->Real *= ScaleFactor;
414  pElement = pElement->NextInRow;
415  }
416  }
417  }
418 
419 /* Scale Columns */
420  pExtOrder = &Matrix->IntToExtColMap[1];
421  for (I = 1; I <= lSize; I++)
422  { if ((ScaleFactor = SolutionScaleFactors[*(pExtOrder++)]) != 1.0)
423  { pElement = Matrix->FirstInCol[I];
424 
425  while (pElement != NULL)
426  { pElement->Real *= ScaleFactor;
427  pElement = pElement->NextInCol;
428  }
429  }
430  }
431  return;
432 
433 #endif /* REAL */
434 }
435 #endif /* SCALING */
436 
437 
438 
439 
440 
441 
442 
443 
444 
445 #if spCOMPLEX AND SCALING
446 /*
447  * SCALE COMPLEX MATRIX
448  *
449  * This function scales the matrix to enhance the possibility of
450  * finding a good pivoting order. Note that scaling enhances accuracy
451  * of the solution only if it affects the pivoting order, so it makes
452  * no sense to scale the matrix before spFactor(). If scaling is
453  * desired it should be done before spOrderAndFactor(). There
454  * are several things to take into account when choosing the scale
455  * factors. First, the scale factors are directly multiplied against
456  * the elements in the matrix. To prevent roundoff, each scale factor
457  * should be equal to an integer power of the number base of the
458  * machine. Since most machines operate in base two, scale factors
459  * should be a power of two. Second, the matrix should be scaled such
460  * that the matrix of element uncertainties is equilibrated. Third,
461  * this function multiplies the scale factors by the elements, so if
462  * one row tends to have uncertainties 1000 times smaller than the
463  * other rows, then its scale factor should be 1024, not 1/1024.
464  * Fourth, to save time, this function does not scale rows or columns
465  * if their scale factors are equal to one. Thus, the scale factors
466  * should be normalized to the most common scale factor. Rows and
467  * columns should be normalized separately. For example, if the size
468  * of the matrix is 100 and 10 rows tend to have uncertainties near
469  * 1e-6 and the remaining 90 have uncertainties near 1e-12, then the
470  * scale factor for the 10 should be 1/1,048,576 and the scale factors
471  * for the remaining 90 should be 1. Fifth, since this routine
472  * directly operates on the matrix, it is necessary to apply the scale
473  * factors to the RHS and Solution vectors. It may be easier to
474  * simply use spOrderAndFactor() on a scaled matrix to choose the
475  * pivoting order, and then throw away the matrix. Subsequent
476  * factorizations, performed with spFactor(), will not need to have
477  * the RHS and Solution vectors descaled. Lastly, this function
478  * should not be executed before the function spMNA_Preorder.
479  *
480  * >>> Arguments:
481  * Matrix <input> (char *)
482  * Pointer to the matrix to be scaled.
483  * SolutionScaleFactors <input> (RealVector)
484  * The array of Solution scale factors. These factors scale the columns.
485  * All scale factors are real valued.
486  * RHS_ScaleFactors <input> (RealVector)
487  * The array of RHS scale factors. These factors scale the rows.
488  * All scale factors are real valued.
489  *
490  * >>> Local variables:
491  * lSize (int)
492  * Local version of the size of the matrix.
493  * pElement (ElementPtr)
494  * Pointer to an element in the matrix.
495  * pExtOrder (int *)
496  * Pointer into either IntToExtRowMap or IntToExtColMap vector. Used to
497  * compensate for any row or column swaps that have been performed.
498  * ScaleFactor (RealNumber)
499  * The scale factor being used on the current row or column.
500  */
501 
502 static void
503 ScaleComplexMatrix( Matrix, RHS_ScaleFactors, SolutionScaleFactors )
504 
506 register RealVector RHS_ScaleFactors, SolutionScaleFactors;
507 {
508 register ElementPtr pElement;
509 register int I, lSize, *pExtOrder;
510 RealNumber ScaleFactor;
511 
512 /* Begin `ScaleComplexMatrix'. */
513  lSize = Matrix->Size;
514 
515 /* Correct pointers to arrays for ARRAY_OFFSET */
516 #if NOT ARRAY_OFFSET
517  --RHS_ScaleFactors;
518  --SolutionScaleFactors;
519 #endif
520 
521 /* Scale Rows */
522  pExtOrder = &Matrix->IntToExtRowMap[1];
523  for (I = 1; I <= lSize; I++)
524  { if ((ScaleFactor = RHS_ScaleFactors[*(pExtOrder++)]) != 1.0)
525  { pElement = Matrix->FirstInRow[I];
526 
527  while (pElement != NULL)
528  { pElement->Real *= ScaleFactor;
529  pElement->Imag *= ScaleFactor;
530  pElement = pElement->NextInRow;
531  }
532  }
533  }
534 
535 /* Scale Columns */
536  pExtOrder = &Matrix->IntToExtColMap[1];
537  for (I = 1; I <= lSize; I++)
538  { if ((ScaleFactor = SolutionScaleFactors[*(pExtOrder++)]) != 1.0)
539  { pElement = Matrix->FirstInCol[I];
540 
541  while (pElement != NULL)
542  { pElement->Real *= ScaleFactor;
543  pElement->Imag *= ScaleFactor;
544  pElement = pElement->NextInCol;
545  }
546  }
547  }
548  return;
549 }
550 #endif /* SCALING AND spCOMPLEX */
551 
552 
553 
554 
555 
556 
557 
558 
559 #if MULTIPLICATION
560 /*
561  * MATRIX MULTIPLICATION
562  *
563  * Multiplies matrix by solution vector to find source vector.
564  * Assumes matrix has not been factored. This routine can be used
565  * as a test to see if solutions are correct. It should not be used
566  * before spMNA_Preorder().
567  *
568  * >>> Arguments:
569  * eMatrix <input> (char *)
570  * Pointer to the matrix.
571  * RHS <output> (RealVector)
572  * RHS is the right hand side. This is what is being solved for.
573  * Solution <input> (RealVector)
574  * Solution is the vector being multiplied by the matrix.
575  * iRHS <output> (RealVector)
576  * iRHS is the imaginary portion of the right hand side. This is
577  * what is being solved for. This is only necessary if the matrix is
578  * complex and spSEPARATED_COMPLEX_VECTORS is true.
579  * iSolution <input> (RealVector)
580  * iSolution is the imaginary portion of the vector being multiplied
581  * by the matrix. This is only necessary if the matrix is
582  * complex and spSEPARATED_COMPLEX_VECTORS is true.
583  *
584  * >>> Obscure Macros
585  * IMAG_VECTORS
586  * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and
587  * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears
588  * without a trace.
589  */
590 
591 void
592 spMultiply( eMatrix, RHS, Solution IMAG_VECTORS )
593 
594 char *eMatrix;
596 {
597 register ElementPtr pElement;
598 register RealVector Vector;
599 register RealNumber Sum;
600 register int I, *pExtOrder;
601 MatrixPtr Matrix = (MatrixPtr)eMatrix;
602 
603 /* Begin `spMultiply'. */
604  ASSERT( IS_SPARSE( Matrix ) AND NOT Matrix->Factored );
605  if (NOT Matrix->RowsLinked) spcLinkRows(Matrix);
606 
607 #if spCOMPLEX
608  if (Matrix->Complex)
609  { ComplexMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS );
610  return;
611  }
612 #endif
613 
614 #if REAL
615 #if NOT ARRAY_OFFSET
616 /* Correct array pointers for ARRAY_OFFSET. */
617  --RHS;
618  --Solution;
619 #endif
620 
621 /* Initialize Intermediate vector with reordered Solution vector. */
622  Vector = Matrix->Intermediate;
623  pExtOrder = &Matrix->IntToExtColMap[Matrix->Size];
624  for (I = Matrix->Size; I > 0; I--)
625  Vector[I] = Solution[*(pExtOrder--)];
626 
627  pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size];
628  for (I = Matrix->Size; I > 0; I--)
629  { pElement = Matrix->FirstInRow[I];
630  Sum = 0.0;
631 
632  while (pElement != NULL)
633  { Sum += pElement->Real * Vector[pElement->Col];
634  pElement = pElement->NextInRow;
635  }
636  RHS[*pExtOrder--] = Sum;
637  }
638  return;
639 #endif /* REAL */
640 }
641 #endif /* MULTIPLICATION */
642 
643 
644 
645 
646 
647 
648 
649 #if spCOMPLEX AND MULTIPLICATION
650 /*
651  * COMPLEX MATRIX MULTIPLICATION
652  *
653  * Multiplies matrix by solution vector to find source vector.
654  * Assumes matrix has not been factored. This routine can be used
655  * as a test to see if solutions are correct.
656  *
657  * >>> Arguments:
658  * Matrix <input> (char *)
659  * Pointer to the matrix.
660  * RHS <output> (RealVector)
661  * RHS is the right hand side. This is what is being solved for.
662  * This is only the real portion of the right-hand side if the matrix
663  * is complex and spSEPARATED_COMPLEX_VECTORS is set true.
664  * Solution <input> (RealVector)
665  * Solution is the vector being multiplied by the matrix. This is only
666  * the real portion if the matrix is complex and
667  * spSEPARATED_COMPLEX_VECTORS is set true.
668  * iRHS <output> (RealVector)
669  * iRHS is the imaginary portion of the right hand side. This is
670  * what is being solved for. This is only necessary if the matrix is
671  * complex and spSEPARATED_COMPLEX_VECTORS is true.
672  * iSolution <input> (RealVector)
673  * iSolution is the imaginary portion of the vector being multiplied
674  * by the matrix. This is only necessary if the matrix is
675  * complex and spSEPARATED_COMPLEX_VECTORS is true.
676  *
677  * >>> Obscure Macros
678  * IMAG_VECTORS
679  * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and
680  * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears
681  * without a trace.
682  */
683 
684 static void
685 ComplexMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS )
686 
688 RealVector RHS, Solution IMAG_VECTORS;
689 {
690 register ElementPtr pElement;
691 register ComplexVector Vector;
692 register ComplexNumber Sum;
693 register int I, *pExtOrder;
694 
695 /* Begin `ComplexMatrixMultiply'. */
696 
697 /* Correct array pointers for ARRAY_OFFSET. */
698 #if NOT ARRAY_OFFSET
699 #if spSEPARATED_COMPLEX_VECTORS
700  --RHS; --iRHS;
701  --Solution; --iSolution;
702 #else
703  RHS -= 2; Solution -= 2;
704 #endif
705 #endif
706 
707 /* Initialize Intermediate vector with reordered Solution vector. */
708  Vector = (ComplexVector)Matrix->Intermediate;
709  pExtOrder = &Matrix->IntToExtColMap[Matrix->Size];
710 
712  for (I = Matrix->Size; I > 0; I--)
713  { Vector[I].Real = Solution[*pExtOrder];
714  Vector[I].Imag = iSolution[*(pExtOrder--)];
715  }
716 #else
717  for (I = Matrix->Size; I > 0; I--)
718  Vector[I] = ((ComplexVector)Solution)[*(pExtOrder--)];
719 #endif
720 
721  pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size];
722  for (I = Matrix->Size; I > 0; I--)
723  { pElement = Matrix->FirstInRow[I];
724  Sum.Real = Sum.Imag = 0.0;
725 
726  while (pElement != NULL)
727  { /* Cmplx expression : Sum += Element * Vector[Col] */
728  CMPLX_MULT_ADD_ASSIGN( Sum, *pElement, Vector[pElement->Col] );
729  pElement = pElement->NextInRow;
730  }
731 
732 #if spSEPARATED_COMPLEX_VECTORS
733  RHS[*pExtOrder] = Sum.Real;
734  iRHS[*pExtOrder--] = Sum.Imag;
735 #else
736  ((ComplexVector)RHS)[*pExtOrder--] = Sum;
737 #endif
738  }
739  return;
740 }
741 #endif /* spCOMPLEX AND MULTIPLICATION */
742 
743 
744 
745 
746 
747 
748 
749 
750 #if MULTIPLICATION AND TRANSPOSE
751 /*
752  * TRANSPOSED MATRIX MULTIPLICATION
753  *
754  * Multiplies transposed matrix by solution vector to find source vector.
755  * Assumes matrix has not been factored. This routine can be used
756  * as a test to see if solutions are correct. It should not be used
757  * before spMNA_Preorder().
758  *
759  * >>> Arguments:
760  * eMatrix <input> (char *)
761  * Pointer to the matrix.
762  * RHS <output> (RealVector)
763  * RHS is the right hand side. This is what is being solved for.
764  * Solution <input> (RealVector)
765  * Solution is the vector being multiplied by the matrix.
766  * iRHS <output> (RealVector)
767  * iRHS is the imaginary portion of the right hand side. This is
768  * what is being solved for. This is only necessary if the matrix is
769  * complex and spSEPARATED_COMPLEX_VECTORS is true.
770  * iSolution <input> (RealVector)
771  * iSolution is the imaginary portion of the vector being multiplied
772  * by the matrix. This is only necessary if the matrix is
773  * complex and spSEPARATED_COMPLEX_VECTORS is true.
774  *
775  * >>> Obscure Macros
776  * IMAG_VECTORS
777  * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and
778  * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears
779  * without a trace.
780  */
781 
782 void
783 spMultTransposed( eMatrix, RHS, Solution IMAG_VECTORS )
784 
785 char *eMatrix;
786 RealVector RHS, Solution IMAG_VECTORS;
787 {
788 register ElementPtr pElement;
789 register RealVector Vector;
790 register RealNumber Sum;
791 register int I, *pExtOrder;
792 MatrixPtr Matrix = (MatrixPtr)eMatrix;
793 
794 /* Begin `spMultTransposed'. */
795  ASSERT( IS_SPARSE( Matrix ) AND NOT Matrix->Factored );
796 
797 #if spCOMPLEX
798  if (Matrix->Complex)
799  { ComplexTransposedMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS );
800  return;
801  }
802 #endif
803 
804 #if REAL
805 #if NOT ARRAY_OFFSET
806 /* Correct array pointers for ARRAY_OFFSET. */
807  --RHS;
808  --Solution;
809 #endif
810 
811 /* Initialize Intermediate vector with reordered Solution vector. */
812  Vector = Matrix->Intermediate;
813  pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size];
814  for (I = Matrix->Size; I > 0; I--)
815  Vector[I] = Solution[*(pExtOrder--)];
816 
817  pExtOrder = &Matrix->IntToExtColMap[Matrix->Size];
818  for (I = Matrix->Size; I > 0; I--)
819  { pElement = Matrix->FirstInCol[I];
820  Sum = 0.0;
821 
822  while (pElement != NULL)
823  { Sum += pElement->Real * Vector[pElement->Row];
824  pElement = pElement->NextInCol;
825  }
826  RHS[*pExtOrder--] = Sum;
827  }
828  return;
829 #endif /* REAL */
830 }
831 #endif /* MULTIPLICATION AND TRANSPOSE */
832 
833 
834 
835 
836 
837 
838 
839 #if spCOMPLEX AND MULTIPLICATION AND TRANSPOSE
840 /*
841  * COMPLEX TRANSPOSED MATRIX MULTIPLICATION
842  *
843  * Multiplies transposed matrix by solution vector to find source vector.
844  * Assumes matrix has not been factored. This routine can be used
845  * as a test to see if solutions are correct.
846  *
847  * >>> Arguments:
848  * Matrix <input> (char *)
849  * Pointer to the matrix.
850  * RHS <output> (RealVector)
851  * RHS is the right hand side. This is what is being solved for.
852  * This is only the real portion of the right-hand side if the matrix
853  * is complex and spSEPARATED_COMPLEX_VECTORS is set true.
854  * Solution <input> (RealVector)
855  * Solution is the vector being multiplied by the matrix. This is only
856  * the real portion if the matrix is complex and
857  * spSEPARATED_COMPLEX_VECTORS is set true.
858  * iRHS <output> (RealVector)
859  * iRHS is the imaginary portion of the right hand side. This is
860  * what is being solved for. This is only necessary if the matrix is
861  * complex and spSEPARATED_COMPLEX_VECTORS is true.
862  * iSolution <input> (RealVector)
863  * iSolution is the imaginary portion of the vector being multiplied
864  * by the matrix. This is only necessary if the matrix is
865  * complex and spSEPARATED_COMPLEX_VECTORS is true.
866  *
867  * >>> Obscure Macros
868  * IMAG_VECTORS
869  * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and
870  * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears
871  * without a trace.
872  */
873 
874 static void
875 ComplexTransposedMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS )
876 
878 RealVector RHS, Solution IMAG_VECTORS;
879 {
880 register ElementPtr pElement;
881 register ComplexVector Vector;
882 register ComplexNumber Sum;
883 register int I, *pExtOrder;
884 
885 /* Begin `ComplexMatrixMultiply'. */
886 
887 /* Correct array pointers for ARRAY_OFFSET. */
888 #if NOT ARRAY_OFFSET
889 #if spSEPARATED_COMPLEX_VECTORS
890  --RHS; --iRHS;
891  --Solution; --iSolution;
892 #else
893  RHS -= 2; Solution -= 2;
894 #endif
895 #endif
896 
897 /* Initialize Intermediate vector with reordered Solution vector. */
898  Vector = (ComplexVector)Matrix->Intermediate;
899  pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size];
900 
902  for (I = Matrix->Size; I > 0; I--)
903  { Vector[I].Real = Solution[*pExtOrder];
904  Vector[I].Imag = iSolution[*(pExtOrder--)];
905  }
906 #else
907  for (I = Matrix->Size; I > 0; I--)
908  Vector[I] = ((ComplexVector)Solution)[*(pExtOrder--)];
909 #endif
910 
911  pExtOrder = &Matrix->IntToExtColMap[Matrix->Size];
912  for (I = Matrix->Size; I > 0; I--)
913  { pElement = Matrix->FirstInCol[I];
914  Sum.Real = Sum.Imag = 0.0;
915 
916  while (pElement != NULL)
917  { /* Cmplx expression : Sum += Element * Vector[Row] */
918  CMPLX_MULT_ADD_ASSIGN( Sum, *pElement, Vector[pElement->Row] );
919  pElement = pElement->NextInCol;
920  }
921 
922 #if spSEPARATED_COMPLEX_VECTORS
923  RHS[*pExtOrder] = Sum.Real;
924  iRHS[*pExtOrder--] = Sum.Imag;
925 #else
926  ((ComplexVector)RHS)[*pExtOrder--] = Sum;
927 #endif
928  }
929  return;
930 }
931 #endif /* spCOMPLEX AND MULTIPLICATION AND TRANSPOSE */
932 
933 
934 
935 
936 
937 
938 
939 
940 #if DETERMINANT
941 /*
942  * CALCULATE DETERMINANT
943  *
944  * This routine in capable of calculating the determinant of the
945  * matrix once the LU factorization has been performed. Hence, only
946  * use this routine after spFactor() and before spClear().
947  * The determinant equals the product of all the diagonal elements of
948  * the lower triangular matrix L, except that this product may need
949  * negating. Whether the product or the negative product equals the
950  * determinant is determined by the number of row and column
951  * interchanges performed. Note that the determinants of matrices can
952  * be very large or very small. On large matrices, the determinant
953  * can be far larger or smaller than can be represented by a floating
954  * point number. For this reason the determinant is scaled to a
955  * reasonable value and the logarithm of the scale factor is returned.
956  *
957  * >>> Arguments:
958  * eMatrix <input> (char *)
959  * A pointer to the matrix for which the determinant is desired.
960  * pExponent <output> (int *)
961  * The logarithm base 10 of the scale factor for the determinant. To find
962  * the actual determinant, Exponent should be added to the exponent of
963  * Determinant.
964  * pDeterminant <output> (RealNumber *)
965  * The real portion of the determinant. This number is scaled to be
966  * greater than or equal to 1.0 and less than 10.0.
967  * piDeterminant <output> (RealNumber *)
968  * The imaginary portion of the determinant. When the matrix is real
969  * this pointer need not be supplied, nothing will be returned. This
970  * number is scaled to be greater than or equal to 1.0 and less than 10.0.
971  *
972  * >>> Local variables:
973  * Norm (RealNumber)
974  * L-infinity norm of a complex number.
975  * Size (int)
976  * Local storage for Matrix->Size. Placed in a register for speed.
977  * Temp (RealNumber)
978  * Temporary storage for real portion of determinant.
979  */
980 
981 #if spCOMPLEX
982 void
983 spDeterminant( eMatrix, pExponent, pDeterminant, piDeterminant )
984 RealNumber *piDeterminant;
985 #else
986 void
987 spDeterminant( eMatrix, pExponent, pDeterminant )
988 #endif
989 
990 char *eMatrix;
991 register RealNumber *pDeterminant;
992 int *pExponent;
993 {
994 register MatrixPtr Matrix = (MatrixPtr)eMatrix;
995 register int I, Size;
996 RealNumber Norm, nr, ni;
997 ComplexNumber Pivot, cDeterminant;
998 
999 #define NORM(a) (nr = ABS((a).Real), ni = ABS((a).Imag), MAX (nr,ni))
1000 
1001 /* Begin `spDeterminant'. */
1002  ASSERT( IS_SPARSE( Matrix ) AND IS_FACTORED(Matrix) );
1003  *pExponent = 0;
1004 
1005  if (Matrix->Error == spSINGULAR)
1006  { *pDeterminant = 0.0;
1007 #if spCOMPLEX
1008  if (Matrix->Complex) *piDeterminant = 0.0;
1009 #endif
1010  return;
1011  }
1012 
1013  Size = Matrix->Size;
1014  I = 0;
1015 
1016 #if spCOMPLEX
1017  if (Matrix->Complex) /* Complex Case. */
1018  { cDeterminant.Real = 1.0;
1019  cDeterminant.Imag = 0.0;
1020 
1021  while (++I <= Size)
1022  { CMPLX_RECIPROCAL( Pivot, *Matrix->Diag[I] );
1023  CMPLX_MULT_ASSIGN( cDeterminant, Pivot );
1024 
1025 /* Scale Determinant. */
1026  Norm = NORM( cDeterminant );
1027  if (Norm != 0.0)
1028  { while (Norm >= 1.0e12)
1029  { cDeterminant.Real *= 1.0e-12;
1030  cDeterminant.Imag *= 1.0e-12;
1031  *pExponent += 12;
1032  Norm = NORM( cDeterminant );
1033  }
1034  while (Norm < 1.0e-12)
1035  { cDeterminant.Real *= 1.0e12;
1036  cDeterminant.Imag *= 1.0e12;
1037  *pExponent -= 12;
1038  Norm = NORM( cDeterminant );
1039  }
1040  }
1041  }
1042 
1043 /* Scale Determinant again, this time to be between 1.0 <= x < 10.0. */
1044  Norm = NORM( cDeterminant );
1045  if (Norm != 0.0)
1046  { while (Norm >= 10.0)
1047  { cDeterminant.Real *= 0.1;
1048  cDeterminant.Imag *= 0.1;
1049  (*pExponent)++;
1050  Norm = NORM( cDeterminant );
1051  }
1052  while (Norm < 1.0)
1053  { cDeterminant.Real *= 10.0;
1054  cDeterminant.Imag *= 10.0;
1055  (*pExponent)--;
1056  Norm = NORM( cDeterminant );
1057  }
1058  }
1059  if (Matrix->NumberOfInterchangesIsOdd)
1060  CMPLX_NEGATE( cDeterminant );
1061 
1062  *pDeterminant = cDeterminant.Real;
1063  *piDeterminant = cDeterminant.Imag;
1064  }
1065 #endif /* spCOMPLEX */
1066 #if REAL AND spCOMPLEX
1067  else
1068 #endif
1069 #if REAL
1070  { /* Real Case. */
1071  *pDeterminant = 1.0;
1072 
1073  while (++I <= Size)
1074  { *pDeterminant /= Matrix->Diag[I]->Real;
1075 
1076 /* Scale Determinant. */
1077  if (*pDeterminant != 0.0)
1078  { while (ABS(*pDeterminant) >= 1.0e12)
1079  { *pDeterminant *= 1.0e-12;
1080  *pExponent += 12;
1081  }
1082  while (ABS(*pDeterminant) < 1.0e-12)
1083  { *pDeterminant *= 1.0e12;
1084  *pExponent -= 12;
1085  }
1086  }
1087  }
1088 
1089 /* Scale Determinant again, this time to be between 1.0 <= x < 10.0. */
1090  if (*pDeterminant != 0.0)
1091  { while (ABS(*pDeterminant) >= 10.0)
1092  { *pDeterminant *= 0.1;
1093  (*pExponent)++;
1094  }
1095  while (ABS(*pDeterminant) < 1.0)
1096  { *pDeterminant *= 10.0;
1097  (*pExponent)--;
1098  }
1099  }
1100  if (Matrix->NumberOfInterchangesIsOdd)
1101  *pDeterminant = -*pDeterminant;
1102  }
1103 #endif /* REAL */
1104 }
1105 #endif /* DETERMINANT */
1106 
1107 
1108 
1109 
1110 
1111 
1112 
1113 
1114 #if STRIP
1115 
1116 /*
1117  * STRIP FILL-INS FROM MATRIX
1118  *
1119  * Strips the matrix of all fill-ins.
1120  *
1121  * >>> Arguments:
1122  * Matrix <input> (char *)
1123  * Pointer to the matrix to be stripped.
1124  *
1125  * >>> Local variables:
1126  * pElement (ElementPtr)
1127  * Pointer that is used to step through the matrix.
1128  * ppElement (ElementPtr *)
1129  * Pointer to the location of an ElementPtr. This location will be
1130  * updated if a fill-in is stripped from the matrix.
1131  * pFillin (ElementPtr)
1132  * Pointer used to step through the lists of fill-ins while marking them.
1133  * pLastFillin (ElementPtr)
1134  * A pointer to the last fill-in in the list. Used to terminate a loop.
1135  * pListNode (struct FillinListNodeStruct *)
1136  * A pointer to a node in the FillinList linked-list.
1137  */
1138 
1139 void
1140 spStripFills( eMatrix )
1141 
1142 char *eMatrix;
1143 {
1144 MatrixPtr Matrix = (MatrixPtr)eMatrix;
1145 struct FillinListNodeStruct *pListNode;
1146 
1147 /* Begin `spStripFills'. */
1148  ASSERT( IS_SPARSE( Matrix ) );
1149  if (Matrix->Fillins == 0) return;
1150  Matrix->NeedsOrdering = YES;
1151  Matrix->Elements -= Matrix->Fillins;
1152  Matrix->Fillins = 0;
1153 
1154 /* Mark the fill-ins. */
1155  { register ElementPtr pFillin, pLastFillin;
1156 
1157  pListNode = Matrix->LastFillinListNode = Matrix->FirstFillinListNode;
1158  Matrix->FillinsRemaining = pListNode->NumberOfFillinsInList;
1159  Matrix->NextAvailFillin = pListNode->pFillinList;
1160 
1161  while (pListNode != NULL)
1162  { pFillin = pListNode->pFillinList;
1163  pLastFillin = &(pFillin[ pListNode->NumberOfFillinsInList - 1 ]);
1164  while (pFillin <= pLastFillin)
1165  (pFillin++)->Row = 0;
1166  pListNode = pListNode->Next;
1167  }
1168  }
1169 
1170 /* Unlink fill-ins by searching for elements marked with Row = 0. */
1171  { register ElementPtr pElement, *ppElement;
1172  register int I, Size = Matrix->Size;
1173 
1174 /* Unlink fill-ins in all columns. */
1175  for (I = 1; I <= Size; I++)
1176  { ppElement = &(Matrix->FirstInCol[I]);
1177  while ((pElement = *ppElement) != NULL)
1178  { if (pElement->Row == 0)
1179  { *ppElement = pElement->NextInCol; /* Unlink fill-in. */
1180  if (Matrix->Diag[pElement->Col] == pElement)
1181  Matrix->Diag[pElement->Col] = NULL;
1182  }
1183  else
1184  ppElement = &pElement->NextInCol; /* Skip element. */
1185  }
1186  }
1187 
1188 /* Unlink fill-ins in all rows. */
1189  for (I = 1; I <= Size; I++)
1190  { ppElement = &(Matrix->FirstInRow[I]);
1191  while ((pElement = *ppElement) != NULL)
1192  { if (pElement->Row == 0)
1193  *ppElement = pElement->NextInRow; /* Unlink fill-in. */
1194  else
1195  ppElement = &pElement->NextInRow; /* Skip element. */
1196  }
1197  }
1198  }
1199  return;
1200 }
1201 #endif
1202 
1203 
1204 
1205 
1206 
1207 
1208 
1209 #if TRANSLATE AND DELETE
1210 /*
1211  * DELETE A ROW AND COLUMN FROM THE MATRIX
1212  *
1213  * Deletes a row and a column from a matrix.
1214  *
1215  * Sparse will abort if an attempt is made to delete a row or column that
1216  * doesn't exist.
1217  *
1218  * >>> Arguments:
1219  * eMatrix <input> (char *)
1220  * Pointer to the matrix in which the row and column are to be deleted.
1221  * Row <input> (int)
1222  * Row to be deleted.
1223  * Col <input> (int)
1224  * Column to be deleted.
1225  *
1226  * >>> Local variables:
1227  * ExtCol (int)
1228  * The external column that is being deleted.
1229  * ExtRow (int)
1230  * The external row that is being deleted.
1231  * pElement (ElementPtr)
1232  * Pointer to an element in the matrix. Used when scanning rows and
1233  * columns in order to eliminate elements from the last row or column.
1234  * ppElement (ElementPtr *)
1235  * Pointer to the location of an ElementPtr. This location will be
1236  * filled with a NULL pointer if it is the new last element in its row
1237  * or column.
1238  * pElement (ElementPtr)
1239  * Pointer to an element in the last row or column of the matrix.
1240  * Size (int)
1241  * The local version Matrix->Size, the size of the matrix.
1242  */
1243 
1244 void
1245 spDeleteRowAndCol( eMatrix, Row, Col )
1246 
1247 char *eMatrix;
1248 int Row, Col;
1249 {
1250 MatrixPtr Matrix = (MatrixPtr)eMatrix;
1251 register ElementPtr pElement, *ppElement, pLastElement;
1252 int Size, ExtRow, ExtCol;
1254 
1255 /* Begin `spDeleteRowAndCol'. */
1256 
1257  ASSERT( IS_SPARSE(Matrix) AND Row > 0 AND Col > 0 );
1258  ASSERT( Row <= Matrix->ExtSize AND Col <= Matrix->ExtSize );
1259 
1260  Size = Matrix->Size;
1261  ExtRow = Row;
1262  ExtCol = Col;
1263  if (NOT Matrix->RowsLinked) spcLinkRows( Matrix );
1264 
1265  Row = Matrix->ExtToIntRowMap[Row];
1266  Col = Matrix->ExtToIntColMap[Col];
1267  ASSERT( Row > 0 AND Col > 0 );
1268 
1269 /* Move Row so that it is the last row in the matrix. */
1270  if (Row != Size) spcRowExchange( Matrix, Row, Size );
1271 
1272 /* Move Col so that it is the last column in the matrix. */
1273  if (Col != Size) spcColExchange( Matrix, Col, Size );
1274 
1275 /* Correct Diag pointers. */
1276  if (Row == Col)
1277  SWAP( ElementPtr, Matrix->Diag[Row], Matrix->Diag[Size] )
1278  else
1279  { Matrix->Diag[Row] = spcFindElementInCol( Matrix, Matrix->FirstInCol+Row,
1280  Row, Row, NO );
1281  Matrix->Diag[Col] = spcFindElementInCol( Matrix, Matrix->FirstInCol+Col,
1282  Col, Col, NO );
1283  }
1284 
1285 /*
1286  * Delete last row and column of the matrix.
1287  */
1288 /* Break the column links to every element in the last row. */
1289  pLastElement = Matrix->FirstInRow[ Size ];
1290  while (pLastElement != NULL)
1291  { ppElement = &(Matrix->FirstInCol[ pLastElement->Col ]);
1292  while ((pElement = *ppElement) != NULL)
1293  { if (pElement == pLastElement)
1294  *ppElement = NULL; /* Unlink last element in column. */
1295  else
1296  ppElement = &pElement->NextInCol; /* Skip element. */
1297  }
1298  pLastElement = pLastElement->NextInRow;
1299  }
1300 
1301 /* Break the row links to every element in the last column. */
1302  pLastElement = Matrix->FirstInCol[ Size ];
1303  while (pLastElement != NULL)
1304  { ppElement = &(Matrix->FirstInRow[ pLastElement->Row ]);
1305  while ((pElement = *ppElement) != NULL)
1306  { if (pElement == pLastElement)
1307  *ppElement = NULL; /* Unlink last element in row. */
1308  else
1309  ppElement = &pElement->NextInRow; /* Skip element. */
1310  }
1311  pLastElement = pLastElement->NextInCol;
1312  }
1313 
1314 /* Clean up some details. */
1315  Matrix->Size = Size - 1;
1316  Matrix->Diag[Size] = NULL;
1317  Matrix->FirstInRow[Size] = NULL;
1318  Matrix->FirstInCol[Size] = NULL;
1319  Matrix->CurrentSize--;
1320  Matrix->ExtToIntRowMap[ExtRow] = -1;
1321  Matrix->ExtToIntColMap[ExtCol] = -1;
1322  Matrix->NeedsOrdering = YES;
1323 
1324  return;
1325 }
1326 #endif
1327 
1328 
1329 
1330 
1331 
1332 
1333 
1334 
1335 #if PSEUDOCONDITION
1336 /*
1337  * CALCULATE PSEUDOCONDITION
1338  *
1339  * Computes the magnitude of the ratio of the largest to the smallest
1340  * pivots. This quantity is an indicator of ill-conditioning in the
1341  * matrix. If this ratio is large, and if the matrix is scaled such
1342  * that uncertainties in the RHS and the matrix entries are
1343  * equilibrated, then the matrix is ill-conditioned. However, a small
1344  * ratio does not necessarily imply that the matrix is
1345  * well-conditioned. This routine must only be used after a matrix has
1346  * been factored by spOrderAndFactor() or spFactor() and before it is
1347  * cleared by spClear() or spInitialize(). The pseudocondition is
1348  * faster to compute than the condition number calculated by
1349  * spCondition(), but is not as informative.
1350  *
1351  * >>> Returns:
1352  * The magnitude of the ratio of the largest to smallest pivot used during
1353  * previous factorization. If the matrix was singular, zero is returned.
1354  *
1355  * >>> Arguments:
1356  * eMatrix <input> (char *)
1357  * Pointer to the matrix.
1358  */
1359 
1360 RealNumber
1362 
1363 char *eMatrix;
1364 {
1365 MatrixPtr Matrix = (MatrixPtr)eMatrix;
1366 register int I;
1367 register ArrayOfElementPtrs Diag;
1368 RealNumber MaxPivot, MinPivot, Mag;
1369 
1370 /* Begin `spPseudoCondition'. */
1371 
1372  ASSERT( IS_SPARSE(Matrix) AND IS_FACTORED(Matrix) );
1373  if (Matrix->Error == spSINGULAR OR Matrix->Error == spZERO_DIAG)
1374  return 0.0;
1375 
1376  Diag = Matrix->Diag;
1377  MaxPivot = MinPivot = ELEMENT_MAG( Diag[1] );
1378  for (I = 2; I <= Matrix->Size; I++)
1379  { Mag = ELEMENT_MAG( Diag[I] );
1380  if (Mag > MaxPivot)
1381  MaxPivot = Mag;
1382  else if (Mag < MinPivot)
1383  MinPivot = Mag;
1384  }
1385  ASSERT( MaxPivot > 0.0);
1386  return MaxPivot / MinPivot;
1387 }
1388 #endif
1389 
1390 
1391 
1392 
1393 
1394 
1395 
1396 
1397 #if CONDITION
1398 /*
1399  * ESTIMATE CONDITION NUMBER
1400  *
1401  * Computes an estimate of the condition number using a variation on
1402  * the LINPACK condition number estimation algorithm. This quantity is
1403  * an indicator of ill-conditioning in the matrix. To avoid problems
1404  * with overflow, the reciprocal of the condition number is returned.
1405  * If this number is small, and if the matrix is scaled such that
1406  * uncertainties in the RHS and the matrix entries are equilibrated,
1407  * then the matrix is ill-conditioned. If the this number is near
1408  * one, the matrix is well conditioned. This routine must only be
1409  * used after a matrix has been factored by spOrderAndFactor() or
1410  * spFactor() and before it is cleared by spClear() or spInitialize().
1411  *
1412  * Unlike the LINPACK condition number estimator, this routines
1413  * returns the L infinity condition number. This is an artifact of
1414  * Sparse placing ones on the diagonal of the upper triangular matrix
1415  * rather than the lower. This difference should be of no importance.
1416  *
1417  * References:
1418  * A.K. Cline, C.B. Moler, G.W. Stewart, J.H. Wilkinson. An estimate
1419  * for the condition number of a matrix. SIAM Journal on Numerical
1420  * Analysis. Vol. 16, No. 2, pages 368-375, April 1979.
1421  *
1422  * J.J. Dongarra, C.B. Moler, J.R. Bunch, G.W. Stewart. LINPACK
1423  * User's Guide. SIAM, 1979.
1424  *
1425  * Roger G. Grimes, John G. Lewis. Condition number estimation for
1426  * sparse matrices. SIAM Journal on Scientific and Statistical
1427  * Computing. Vol. 2, No. 4, pages 384-388, December 1981.
1428  *
1429  * Dianne Prost O'Leary. Estimating matrix condition numbers. SIAM
1430  * Journal on Scientific and Statistical Computing. Vol. 1, No. 2,
1431  * pages 205-209, June 1980.
1432  *
1433  * >>> Returns:
1434  * The reciprocal of the condition number. If the matrix was singular,
1435  * zero is returned.
1436  *
1437  * >>> Arguments:
1438  * eMatrix <input> (char *)
1439  * Pointer to the matrix.
1440  * NormOfMatrix <input> (RealNumber)
1441  * The L-infinity norm of the unfactored matrix as computed by
1442  * spNorm().
1443  * pError <output> (int *)
1444  * Used to return error code.
1445  *
1446  * >>> Possible errors:
1447  * spSINGULAR
1448  * spNO_MEMORY
1449  */
1450 
1451 RealNumber
1452 spCondition( eMatrix, NormOfMatrix, pError )
1453 
1454 char *eMatrix;
1455 RealNumber NormOfMatrix;
1456 int *pError;
1457 {
1458 MatrixPtr Matrix = (MatrixPtr)eMatrix;
1459 register ElementPtr pElement;
1460 register RealVector T, Tm;
1461 register int I, K, Row;
1463 int Size;
1464 RealNumber E, Em, Wp, Wm, ASp, ASm, ASw, ASy, ASv, ASz, MaxY, ScaleFactor;
1465 RealNumber Linpack, OLeary, InvNormOfInverse;
1466 #define SLACK 1e4
1467 
1468 /* Begin `spCondition'. */
1469 
1470  ASSERT( IS_SPARSE(Matrix) AND IS_FACTORED(Matrix) );
1471  *pError = Matrix->Error;
1472  if (Matrix->Error >= spFATAL) return 0.0;
1473  if (NormOfMatrix == 0.0)
1474  { *pError = spSINGULAR;
1475  return 0.0;
1476  }
1477 
1478 #if spCOMPLEX
1479  if (Matrix->Complex)
1480  return ComplexCondition( Matrix, NormOfMatrix, pError );
1481 #endif
1482 
1483 #if REAL
1484  Size = Matrix->Size;
1485  T = Matrix->Intermediate;
1486 #if spCOMPLEX
1487  Tm = Matrix->Intermediate + Size;
1488 #else
1489  Tm = ALLOC( RealNumber, Size+1 );
1490  if (Tm == NULL)
1491  { *pError = spNO_MEMORY;
1492  return 0.0;
1493  }
1494 #endif
1495  for (I = Size; I > 0; I--) T[I] = 0.0;
1496 
1497 /*
1498  * Part 1. Ay = e.
1499  * Solve Ay = LUy = e where e consists of +1 and -1 terms with the sign
1500  * chosen to maximize the size of w in Lw = e. Since the terms in w can
1501  * get very large, scaling is used to avoid overflow.
1502  */
1503 
1504 /* Forward elimination. Solves Lw = e while choosing e. */
1505  E = 1.0;
1506  for (I = 1; I <= Size; I++)
1507  { pPivot = Matrix->Diag[I];
1508  if (T[I] < 0.0) Em = -E; else Em = E;
1509  Wm = (Em + T[I]) * pPivot->Real;
1510  if (ABS(Wm) > SLACK)
1511  { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(Wm) );
1512  for (K = Size; K > 0; K--) T[K] *= ScaleFactor;
1513  E *= ScaleFactor;
1514  Em *= ScaleFactor;
1515  Wm = (Em + T[I]) * pPivot->Real;
1516  }
1517  Wp = (T[I] - Em) * pPivot->Real;
1518  ASp = ABS(T[I] - Em);
1519  ASm = ABS(Em + T[I]);
1520 
1521 /* Update T for both values of W, minus value is placed in Tm. */
1522  pElement = pPivot->NextInCol;
1523  while (pElement != NULL)
1524  { Row = pElement->Row;
1525  Tm[Row] = T[Row] - (Wm * pElement->Real);
1526  T[Row] -= (Wp * pElement->Real);
1527  ASp += ABS(T[Row]);
1528  ASm += ABS(Tm[Row]);
1529  pElement = pElement->NextInCol;
1530  }
1531 
1532 /* If minus value causes more growth, overwrite T with its values. */
1533  if (ASm > ASp)
1534  { T[I] = Wm;
1535  pElement = pPivot->NextInCol;
1536  while (pElement != NULL)
1537  { T[pElement->Row] = Tm[pElement->Row];
1538  pElement = pElement->NextInCol;
1539  }
1540  }
1541  else T[I] = Wp;
1542  }
1543 
1544 /* Compute 1-norm of T, which now contains w, and scale ||T|| to 1/SLACK. */
1545  for (ASw = 0.0, I = Size; I > 0; I--) ASw += ABS(T[I]);
1546  ScaleFactor = 1.0 / (SLACK * ASw);
1547  if (ScaleFactor < 0.5)
1548  { for (I = Size; I > 0; I--) T[I] *= ScaleFactor;
1549  E *= ScaleFactor;
1550  }
1551 
1552 /* Backward Substitution. Solves Uy = w.*/
1553  for (I = Size; I >= 1; I--)
1554  { pElement = Matrix->Diag[I]->NextInRow;
1555  while (pElement != NULL)
1556  { T[I] -= pElement->Real * T[pElement->Col];
1557  pElement = pElement->NextInRow;
1558  }
1559  if (ABS(T[I]) > SLACK)
1560  { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) );
1561  for (K = Size; K > 0; K--) T[K] *= ScaleFactor;
1562  E *= ScaleFactor;
1563  }
1564  }
1565 
1566 /* Compute 1-norm of T, which now contains y, and scale ||T|| to 1/SLACK. */
1567  for (ASy = 0.0, I = Size; I > 0; I--) ASy += ABS(T[I]);
1568  ScaleFactor = 1.0 / (SLACK * ASy);
1569  if (ScaleFactor < 0.5)
1570  { for (I = Size; I > 0; I--) T[I] *= ScaleFactor;
1571  ASy = 1.0 / SLACK;
1572  E *= ScaleFactor;
1573  }
1574 
1575 /* Compute infinity-norm of T for O'Leary's estimate. */
1576  for (MaxY = 0.0, I = Size; I > 0; I--)
1577  if (MaxY < ABS(T[I])) MaxY = ABS(T[I]);
1578 
1579 /*
1580  * Part 2. A* z = y where the * represents the transpose.
1581  * Recall that A = LU implies A* = U* L*.
1582  */
1583 
1584 /* Forward elimination, U* v = y. */
1585  for (I = 1; I <= Size; I++)
1586  { pElement = Matrix->Diag[I]->NextInRow;
1587  while (pElement != NULL)
1588  { T[pElement->Col] -= T[I] * pElement->Real;
1589  pElement = pElement->NextInRow;
1590  }
1591  if (ABS(T[I]) > SLACK)
1592  { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) );
1593  for (K = Size; K > 0; K--) T[K] *= ScaleFactor;
1594  ASy *= ScaleFactor;
1595  }
1596  }
1597 
1598 /* Compute 1-norm of T, which now contains v, and scale ||T|| to 1/SLACK. */
1599  for (ASv = 0.0, I = Size; I > 0; I--) ASv += ABS(T[I]);
1600  ScaleFactor = 1.0 / (SLACK * ASv);
1601  if (ScaleFactor < 0.5)
1602  { for (I = Size; I > 0; I--) T[I] *= ScaleFactor;
1603  ASy *= ScaleFactor;
1604  }
1605 
1606 /* Backward Substitution, L* z = v. */
1607  for (I = Size; I >= 1; I--)
1608  { pPivot = Matrix->Diag[I];
1609  pElement = pPivot->NextInCol;
1610  while (pElement != NULL)
1611  { T[I] -= pElement->Real * T[pElement->Row];
1612  pElement = pElement->NextInCol;
1613  }
1614  T[I] *= pPivot->Real;
1615  if (ABS(T[I]) > SLACK)
1616  { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) );
1617  for (K = Size; K > 0; K--) T[K] *= ScaleFactor;
1618  ASy *= ScaleFactor;
1619  }
1620  }
1621 
1622 /* Compute 1-norm of T, which now contains z. */
1623  for (ASz = 0.0, I = Size; I > 0; I--) ASz += ABS(T[I]);
1624 
1625 #if NOT spCOMPLEX
1626  FREE( Tm );
1627 #endif
1628 
1629  Linpack = ASy / ASz;
1630  OLeary = E / MaxY;
1631  InvNormOfInverse = MIN( Linpack, OLeary );
1632  return InvNormOfInverse / NormOfMatrix;
1633 #endif /* REAL */
1634 }
1635 
1636 
1637 
1638 
1639 
1640 #if spCOMPLEX
1641 /*
1642  * ESTIMATE CONDITION NUMBER
1643  *
1644  * Complex version of spCondition().
1645  *
1646  * >>> Returns:
1647  * The reciprocal of the condition number.
1648  *
1649  * >>> Arguments:
1650  * Matrix <input> (MatrixPtr)
1651  * Pointer to the matrix.
1652  * NormOfMatrix <input> (RealNumber)
1653  * The L-infinity norm of the unfactored matrix as computed by
1654  * spNorm().
1655  * pError <output> (int *)
1656  * Used to return error code.
1657  *
1658  * >>> Possible errors:
1659  * spNO_MEMORY
1660  */
1661 
1662 static RealNumber
1663 ComplexCondition( Matrix, NormOfMatrix, pError )
1664 
1666 RealNumber NormOfMatrix;
1667 int *pError;
1668 {
1669 register ElementPtr pElement;
1670 register ComplexVector T, Tm;
1671 register int I, K, Row;
1673 int Size;
1674 RealNumber E, Em, ASp, ASm, ASw, ASy, ASv, ASz, MaxY, ScaleFactor;
1675 RealNumber Linpack, OLeary, InvNormOfInverse;
1676 ComplexNumber Wp, Wm;
1677 
1678 /* Begin `ComplexCondition'. */
1679 
1680  Size = Matrix->Size;
1681  T = (ComplexVector)Matrix->Intermediate;
1682  Tm = ALLOC( ComplexNumber, Size+1 );
1683  if (Tm == NULL)
1684  { *pError = spNO_MEMORY;
1685  return 0.0;
1686  }
1687  for (I = Size; I > 0; I--) T[I].Real = T[I].Imag = 0.0;
1688 
1689 /*
1690  * Part 1. Ay = e.
1691  * Solve Ay = LUy = e where e consists of +1 and -1 terms with the sign
1692  * chosen to maximize the size of w in Lw = e. Since the terms in w can
1693  * get very large, scaling is used to avoid overflow.
1694  */
1695 
1696 /* Forward elimination. Solves Lw = e while choosing e. */
1697  E = 1.0;
1698  for (I = 1; I <= Size; I++)
1699  { pPivot = Matrix->Diag[I];
1700  if (T[I].Real < 0.0) Em = -E; else Em = E;
1701  Wm = T[I];
1702  Wm.Real += Em;
1703  ASm = CMPLX_1_NORM( Wm );
1704  CMPLX_MULT_ASSIGN( Wm, *pPivot );
1705  if (CMPLX_1_NORM(Wm) > SLACK)
1706  { ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(Wm) );
1707  for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor );
1708  E *= ScaleFactor;
1709  Em *= ScaleFactor;
1710  ASm *= ScaleFactor;
1711  SCLR_MULT_ASSIGN( Wm, ScaleFactor );
1712  }
1713  Wp = T[I];
1714  Wp.Real -= Em;
1715  ASp = CMPLX_1_NORM( Wp );
1716  CMPLX_MULT_ASSIGN( Wp, *pPivot );
1717 
1718 /* Update T for both values of W, minus value is placed in Tm. */
1719  pElement = pPivot->NextInCol;
1720  while (pElement != NULL)
1721  { Row = pElement->Row;
1722  /* Cmplx expr: Tm[Row] = T[Row] - (Wp * *pElement). */
1723  CMPLX_MULT_SUBT( Tm[Row], Wm, *pElement, T[Row] );
1724  /* Cmplx expr: T[Row] -= Wp * *pElement. */
1725  CMPLX_MULT_SUBT_ASSIGN( T[Row], Wm, *pElement );
1726  ASp += CMPLX_1_NORM(T[Row]);
1727  ASm += CMPLX_1_NORM(Tm[Row]);
1728  pElement = pElement->NextInCol;
1729  }
1730 
1731 /* If minus value causes more growth, overwrite T with its values. */
1732  if (ASm > ASp)
1733  { T[I] = Wm;
1734  pElement = pPivot->NextInCol;
1735  while (pElement != NULL)
1736  { T[pElement->Row] = Tm[pElement->Row];
1737  pElement = pElement->NextInCol;
1738  }
1739  }
1740  else T[I] = Wp;
1741  }
1742 
1743 /* Compute 1-norm of T, which now contains w, and scale ||T|| to 1/SLACK. */
1744  for (ASw = 0.0, I = Size; I > 0; I--) ASw += CMPLX_1_NORM(T[I]);
1745  ScaleFactor = 1.0 / (SLACK * ASw);
1746  if (ScaleFactor < 0.5)
1747  { for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor );
1748  E *= ScaleFactor;
1749  }
1750 
1751 /* Backward Substitution. Solves Uy = w.*/
1752  for (I = Size; I >= 1; I--)
1753  { pElement = Matrix->Diag[I]->NextInRow;
1754  while (pElement != NULL)
1755  { /* Cmplx expr: T[I] -= T[pElement->Col] * *pElement. */
1756  CMPLX_MULT_SUBT_ASSIGN( T[I], T[pElement->Col], *pElement );
1757  pElement = pElement->NextInRow;
1758  }
1759  if (CMPLX_1_NORM(T[I]) > SLACK)
1760  { ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(T[I]) );
1761  for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor );
1762  E *= ScaleFactor;
1763  }
1764  }
1765 
1766 /* Compute 1-norm of T, which now contains y, and scale ||T|| to 1/SLACK. */
1767  for (ASy = 0.0, I = Size; I > 0; I--) ASy += CMPLX_1_NORM(T[I]);
1768  ScaleFactor = 1.0 / (SLACK * ASy);
1769  if (ScaleFactor < 0.5)
1770  { for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor );
1771  ASy = 1.0 / SLACK;
1772  E *= ScaleFactor;
1773  }
1774 
1775 /* Compute infinity-norm of T for O'Leary's estimate. */
1776  for (MaxY = 0.0, I = Size; I > 0; I--)
1777  if (MaxY < CMPLX_1_NORM(T[I])) MaxY = CMPLX_1_NORM(T[I]);
1778 
1779 /*
1780  * Part 2. A* z = y where the * represents the transpose.
1781  * Recall that A = LU implies A* = U* L*.
1782  */
1783 
1784 /* Forward elimination, U* v = y. */
1785  for (I = 1; I <= Size; I++)
1786  { pElement = Matrix->Diag[I]->NextInRow;
1787  while (pElement != NULL)
1788  { /* Cmplx expr: T[pElement->Col] -= T[I] * *pElement. */
1789  CMPLX_MULT_SUBT_ASSIGN( T[pElement->Col], T[I], *pElement );
1790  pElement = pElement->NextInRow;
1791  }
1792  if (CMPLX_1_NORM(T[I]) > SLACK)
1793  { ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(T[I]) );
1794  for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor );
1795  ASy *= ScaleFactor;
1796  }
1797  }
1798 
1799 /* Compute 1-norm of T, which now contains v, and scale ||T|| to 1/SLACK. */
1800  for (ASv = 0.0, I = Size; I > 0; I--) ASv += CMPLX_1_NORM(T[I]);
1801  ScaleFactor = 1.0 / (SLACK * ASv);
1802  if (ScaleFactor < 0.5)
1803  { for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor );
1804  ASy *= ScaleFactor;
1805  }
1806 
1807 /* Backward Substitution, L* z = v. */
1808  for (I = Size; I >= 1; I--)
1809  { pPivot = Matrix->Diag[I];
1810  pElement = pPivot->NextInCol;
1811  while (pElement != NULL)
1812  { /* Cmplx expr: T[I] -= T[pElement->Row] * *pElement. */
1813  CMPLX_MULT_SUBT_ASSIGN( T[I], T[pElement->Row], *pElement );
1814  pElement = pElement->NextInCol;
1815  }
1816  CMPLX_MULT_ASSIGN( T[I], *pPivot );
1817  if (CMPLX_1_NORM(T[I]) > SLACK)
1818  { ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(T[I]) );
1819  for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor );
1820  ASy *= ScaleFactor;
1821  }
1822  }
1823 
1824 /* Compute 1-norm of T, which now contains z. */
1825  for (ASz = 0.0, I = Size; I > 0; I--) ASz += CMPLX_1_NORM(T[I]);
1826 
1827  FREE( Tm );
1828 
1829  Linpack = ASy / ASz;
1830  OLeary = E / MaxY;
1831  InvNormOfInverse = MIN( Linpack, OLeary );
1832  return InvNormOfInverse / NormOfMatrix;
1833 }
1834 #endif /* spCOMPLEX */
1835 
1836 
1837 
1838 
1839 
1840 /*
1841  * L-INFINITY MATRIX NORM
1842  *
1843  * Computes the L-infinity norm of an unfactored matrix. It is a fatal
1844  * error to pass this routine a factored matrix.
1845  *
1846  * One difficulty is that the rows may not be linked.
1847  *
1848  * >>> Returns:
1849  * The largest absolute row sum of matrix.
1850  *
1851  * >>> Arguments:
1852  * eMatrix <input> (char *)
1853  * Pointer to the matrix.
1854  */
1855 
1856 RealNumber
1857 spNorm( eMatrix )
1858 
1859 char *eMatrix;
1860 {
1861 MatrixPtr Matrix = (MatrixPtr)eMatrix;
1862 register ElementPtr pElement;
1863 register int I;
1864 RealNumber Max = 0.0, AbsRowSum;
1865 
1866 /* Begin `spNorm'. */
1867  ASSERT( IS_SPARSE(Matrix) AND NOT IS_FACTORED(Matrix) );
1868  if (NOT Matrix->RowsLinked) spcLinkRows( Matrix );
1869 
1870 /* Compute row sums. */
1871 #if REAL
1872  if (NOT Matrix->Complex)
1873  { for (I = Matrix->Size; I > 0; I--)
1874  { pElement = Matrix->FirstInRow[I];
1875  AbsRowSum = 0.0;
1876  while (pElement != NULL)
1877  { AbsRowSum += ABS( pElement->Real );
1878  pElement = pElement->NextInRow;
1879  }
1880  if (Max < AbsRowSum) Max = AbsRowSum;
1881  }
1882  }
1883 #endif
1884 #if spCOMPLEX
1885  if (Matrix->Complex)
1886  { for (I = Matrix->Size; I > 0; I--)
1887  { pElement = Matrix->FirstInRow[I];
1888  AbsRowSum = 0.0;
1889  while (pElement != NULL)
1890  { AbsRowSum += CMPLX_1_NORM( *pElement );
1891  pElement = pElement->NextInRow;
1892  }
1893  if (Max < AbsRowSum) Max = AbsRowSum;
1894  }
1895  }
1896 #endif
1897  return Max;
1898 }
1899 #endif /* CONDITION */
1900 
1901 
1902 
1903 
1904 
1905 
1906 #if STABILITY
1907 /*
1908  * STABILITY OF FACTORIZATION
1909  *
1910  * The following routines are used to gauge the stability of a
1911  * factorization. If the factorization is determined to be too unstable,
1912  * then the matrix should be reordered. The routines compute quantities
1913  * that are needed in the computation of a bound on the error attributed
1914  * to any one element in the matrix during the factorization. In other
1915  * words, there is a matrix E = [e_ij] of error terms such that A+E = LU.
1916  * This routine finds a bound on |e_ij|. Erisman & Reid [1] showed that
1917  * |e_ij| < 3.01 u rho m_ij, where u is the machine rounding unit,
1918  * rho = max a_ij where the max is taken over every row i, column j, and
1919  * step k, and m_ij is the number of multiplications required in the
1920  * computation of l_ij if i > j or u_ij otherwise. Barlow [2] showed that
1921  * rho < max_i || l_i ||_p max_j || u_j ||_q where 1/p + 1/q = 1.
1922  *
1923  * The first routine finds the magnitude on the largest element in the
1924  * matrix. If the matrix has not yet been factored, the largest
1925  * element is found by direct search. If the matrix is factored, a
1926  * bound on the largest element in any of the reduced submatrices is
1927  * computed using Barlow with p = oo and q = 1. The ratio of these
1928  * two numbers is the growth, which can be used to determine if the
1929  * pivoting order is adequate. A large growth implies that
1930  * considerable error has been made in the factorization and that it
1931  * is probably a good idea to reorder the matrix. If a large growth
1932  * in encountered after using spFactor(), reconstruct the matrix and
1933  * refactor using spOrderAndFactor(). If a large growth is
1934  * encountered after using spOrderAndFactor(), refactor using
1935  * spOrderAndFactor() with the pivot threshold increased, say to 0.1.
1936  *
1937  * Using only the size of the matrix as an upper bound on m_ij and
1938  * Barlow's bound, the user can estimate the size of the matrix error
1939  * terms e_ij using the bound of Erisman and Reid. The second routine
1940  * computes a tighter bound (with more work) based on work by Gear
1941  * [3], |e_ij| < 1.01 u rho (t c^3 + (1 + t)c^2) where t is the
1942  * threshold and c is the maximum number of off-diagonal elements in
1943  * any row of L. The expensive part of computing this bound is
1944  * determining the maximum number of off-diagonals in L, which changes
1945  * only when the order of the matrix changes. This number is computed
1946  * and saved, and only recomputed if the matrix is reordered.
1947  *
1948  * [1] A. M. Erisman, J. K. Reid. Monitoring the stability of the
1949  * triangular factorization of a sparse matrix. Numerische
1950  * Mathematik. Vol. 22, No. 3, 1974, pp 183-186.
1951  *
1952  * [2] J. L. Barlow. A note on monitoring the stability of triangular
1953  * decomposition of sparse matrices. "SIAM Journal of Scientific
1954  * and Statistical Computing." Vol. 7, No. 1, January 1986, pp 166-168.
1955  *
1956  * [3] I. S. Duff, A. M. Erisman, J. K. Reid. "Direct Methods for Sparse
1957  * Matrices." Oxford 1986. pp 99.
1958  */
1959 
1960 /*
1961  * LARGEST ELEMENT IN MATRIX
1962  *
1963  * >>> Returns:
1964  * If matrix is not factored, returns the magnitude of the largest element in
1965  * the matrix. If the matrix is factored, a bound on the magnitude of the
1966  * largest element in any of the reduced submatrices is returned.
1967  *
1968  * >>> Arguments:
1969  * eMatrix <input> (char *)
1970  * Pointer to the matrix.
1971  */
1972 
1973 RealNumber
1975 
1976 char *eMatrix;
1977 {
1978 MatrixPtr Matrix = (MatrixPtr)eMatrix;
1979 register int I;
1980 RealNumber Mag, AbsColSum, Max = 0.0, MaxRow = 0.0, MaxCol = 0.0;
1981 RealNumber Pivot;
1982 ComplexNumber cPivot;
1983 register ElementPtr pElement, pDiag;
1984 
1985 /* Begin `spLargestElement'. */
1986  ASSERT( IS_SPARSE(Matrix) );
1987 
1988 #if REAL
1989  if (Matrix->Factored AND NOT Matrix->Complex)
1990  { if (Matrix->Error == spSINGULAR) return 0.0;
1991 
1992 /* Find the bound on the size of the largest element over all factorization. */
1993  for (I = 1; I <= Matrix->Size; I++)
1994  { pDiag = Matrix->Diag[I];
1995 
1996 /* Lower triangular matrix. */
1997  Pivot = 1.0 / pDiag->Real;
1998  Mag = ABS( Pivot );
1999  if (Mag > MaxRow) MaxRow = Mag;
2000  pElement = Matrix->FirstInRow[I];
2001  while (pElement != pDiag)
2002  { Mag = ABS( pElement->Real );
2003  if (Mag > MaxRow) MaxRow = Mag;
2004  pElement = pElement->NextInRow;
2005  }
2006 
2007 /* Upper triangular matrix. */
2008  pElement = Matrix->FirstInCol[I];
2009  AbsColSum = 1.0; /* Diagonal of U is unity. */
2010  while (pElement != pDiag)
2011  { AbsColSum += ABS( pElement->Real );
2012  pElement = pElement->NextInCol;
2013  }
2014  if (AbsColSum > MaxCol) MaxCol = AbsColSum;
2015  }
2016  }
2017  else if (NOT Matrix->Complex)
2018  { for (I = 1; I <= Matrix->Size; I++)
2019  { pElement = Matrix->FirstInCol[I];
2020  while (pElement != NULL)
2021  { Mag = ABS( pElement->Real );
2022  if (Mag > Max) Max = Mag;
2023  pElement = pElement->NextInCol;
2024  }
2025  }
2026  return Max;
2027  }
2028 #endif
2029 #if spCOMPLEX
2030  if (Matrix->Factored AND Matrix->Complex)
2031  { if (Matrix->Error == spSINGULAR) return 0.0;
2032 
2033 /* Find the bound on the size of the largest element over all factorization. */
2034  for (I = 1; I <= Matrix->Size; I++)
2035  { pDiag = Matrix->Diag[I];
2036 
2037 /* Lower triangular matrix. */
2038  CMPLX_RECIPROCAL( cPivot, *pDiag );
2039  Mag = CMPLX_1_NORM( cPivot );
2040  if (Mag > MaxRow) MaxRow = Mag;
2041  pElement = Matrix->FirstInRow[I];
2042  while (pElement != pDiag)
2043  { Mag = CMPLX_1_NORM( *pElement );
2044  if (Mag > MaxRow) MaxRow = Mag;
2045  pElement = pElement->NextInRow;
2046  }
2047 
2048 /* Upper triangular matrix. */
2049  pElement = Matrix->FirstInCol[I];
2050  AbsColSum = 1.0; /* Diagonal of U is unity. */
2051  while (pElement != pDiag)
2052  { AbsColSum += CMPLX_1_NORM( *pElement );
2053  pElement = pElement->NextInCol;
2054  }
2055  if (AbsColSum > MaxCol) MaxCol = AbsColSum;
2056  }
2057  }
2058  else if (Matrix->Complex)
2059  { for (I = 1; I <= Matrix->Size; I++)
2060  { pElement = Matrix->FirstInCol[I];
2061  while (pElement != NULL)
2062  { Mag = CMPLX_1_NORM( *pElement );
2063  if (Mag > Max) Max = Mag;
2064  pElement = pElement->NextInCol;
2065  }
2066  }
2067  return Max;
2068  }
2069 #endif
2070  return MaxRow * MaxCol;
2071 }
2072 
2073 
2074 
2075 
2076 /*
2077  * MATRIX ROUNDOFF ERROR
2078  *
2079  * >>> Returns:
2080  * Returns a bound on the magnitude of the largest element in E = A - LU.
2081  *
2082  * >>> Arguments:
2083  * eMatrix <input> (char *)
2084  * Pointer to the matrix.
2085  * Rho <input> (RealNumber)
2086  * The bound on the magnitude of the largest element in any of the
2087  * reduced submatrices. This is the number computed by the function
2088  * spLargestElement() when given a factored matrix. If this number is
2089  * negative, the bound will be computed automatically.
2090  */
2091 
2092 RealNumber
2093 spRoundoff( eMatrix, Rho )
2094 
2095 char *eMatrix;
2096 RealNumber Rho;
2097 {
2098 MatrixPtr Matrix = (MatrixPtr)eMatrix;
2099 register ElementPtr pElement;
2100 register int Count, I, MaxCount = 0;
2101 RealNumber Reid, Gear;
2102 
2103 /* Begin `spRoundoff'. */
2104  ASSERT( IS_SPARSE(Matrix) AND IS_FACTORED(Matrix) );
2105 
2106 /* Compute Barlow's bound if it is not given. */
2107  if (Rho < 0.0) Rho = spLargestElement( eMatrix );
2108 
2109 /* Find the maximum number of off-diagonals in L if not previously computed. */
2110  if (Matrix->MaxRowCountInLowerTri < 0)
2111  { for (I = Matrix->Size; I > 0; I--)
2112  { pElement = Matrix->FirstInRow[I];
2113  Count = 0;
2114  while (pElement->Col < I)
2115  { Count++;
2116  pElement = pElement->NextInRow;
2117  }
2118  if (Count > MaxCount) MaxCount = Count;
2119  }
2120  Matrix->MaxRowCountInLowerTri = MaxCount;
2121  }
2122  else MaxCount = Matrix->MaxRowCountInLowerTri;
2123 
2124 /* Compute error bound. */
2125  Gear = 1.01*((MaxCount + 1) * Matrix->RelThreshold + 1.0) * SQR(MaxCount);
2126  Reid = 3.01 * Matrix->Size;
2127 
2128  if (Gear < Reid)
2129  return (MACHINE_RESOLUTION * Rho * Gear);
2130  else
2131  return (MACHINE_RESOLUTION * Rho * Reid);
2132 }
2133 #endif
ArrayOfElementPtrs FirstInRow
Definition: spdefs.h:845
void spMultTransposed(eMatrix, RHS, Solution IMAG_VECTORS) char *eMatrix
#define CMPLX_MULT_ASSIGN(to, from)
Definition: spdefs.h:226
if(NOT Matrix->RowsLinked) spcLinkRows(Matrix)
double T
Definition: rbtqueue.cpp:25
#define ALLOC(type, number)
Definition: spdefs.h:442
ElementPtr pFillinList
Definition: spdefs.h:625
RealNumber RelThreshold
Definition: spdefs.h:862
#define CMPLX_MULT_SUBT(to, mult_a, mult_b, subt)
Definition: spdefs.h:254
#define IS_FACTORED(matrix)
Definition: spdefs.h:126
#define NO
Definition: spdefs.h:108
#define Real
Definition: machine.h:189
void spDeterminant(char *eMatrix, int *pExponent, RealNumber *pDeterminant)
Definition: sputils.c:987
#define BOOLEAN
Definition: spdefs.h:107
#define SLACK
ArrayOfElementPtrs Diag
Definition: spdefs.h:834
#define spSEPARATED_COMPLEX_VECTORS
Definition: spconfig.h:286
#define NOT
Definition: spdefs.h:110
#define spSINGULAR
Definition: spmatrix.h:100
int NumberOfFillinsInList
Definition: spdefs.h:626
int * ExtToIntColMap
Definition: spdefs.h:840
BOOLEAN RowsLinked
Definition: spdefs.h:864
#define spFATAL
Definition: spmatrix.h:104
RealVector Intermediate
Definition: spdefs.h:847
void spDeleteRowAndCol(char *eMatrix, int Row, int Col)
Definition: sputils.c:1245
void spMNA_Preorder(char *eMatrix)
Definition: sputils.c:184
RealVector Solution IMAG_VECTORS
Definition: sputils.c:595
#define e
Definition: passive0.cpp:24
struct FillinListNodeStruct * Next
Definition: spdefs.h:627
ArrayOfElementPtrs FirstInCol
Definition: spdefs.h:844
#define FREE(ptr)
Definition: spdefs.h:446
spREAL * RealVector
Definition: spdefs.h:468
RealVector RHS
Definition: sputils.c:595
register RealNumber Sum
Definition: sputils.c:599
struct ComplexNumber * ComplexVector
#define ABS(x)
Definition: extras.c:201
#define OR
Definition: spdefs.h:112
#define IS_SPARSE(matrix)
Definition: spdefs.h:120
struct MatrixElement * NextInRow
Definition: spdefs.h:555
RealNumber spRoundoff(char *eMatrix, RealNumber Rho)
Definition: sputils.c:2093
#define ELEMENT_MAG(ptr)
Definition: spdefs.h:146
BOOLEAN NeedsOrdering
Definition: spdefs.h:855
#define CMPLX_MULT_SUBT_ASSIGN(to, from_a, from_b)
Definition: spdefs.h:282
#define CMPLX_NEGATE(a)
Definition: spdefs.h:167
void spMultiply(eMatrix, RHS, Solution IMAG_VECTORS) char *eMatrix
RealNumber Real
Definition: spdefs.h:549
#define MAX(a, b)
Definition: grids.h:31
int * IntToExtColMap
Definition: spdefs.h:849
#define AND
Definition: spdefs.h:111
#define NORM(a)
#define IS_VALID(matrix)
Definition: spdefs.h:122
RealNumber spCondition(char *eMatrix, RealNumber NormOfMatrix, int *pError)
Definition: sputils.c:1452
RealNumber Real
Definition: spdefs.h:492
RealNumber spLargestElement(char *eMatrix)
Definition: sputils.c:1974
for(I=Matrix->Size;I, 0;I--)
Definition: sputils.c:624
register ElementPtr pElement
Definition: spsolve.c:139
#define CMPLX_MULT_ADD_ASSIGN(to, from_a, from_b)
Definition: spdefs.h:273
struct FillinListNodeStruct * LastFillinListNode
Definition: spdefs.h:878
BOOLEAN NumberOfInterchangesIsOdd
Definition: spdefs.h:856
#define CMPLX_1_NORM(a)
Definition: spdefs.h:173
void spcRowExchange(MatrixPtr, int row1, int row2)
Definition: spfactor.c:2234
int Error
Definition: spdefs.h:838
int Fillins
Definition: spdefs.h:843
int Size
Definition: spdefs.h:868
static void ComplexMatrixMultiply()
Definition: utility.h:67
RealNumber Imag
Definition: spdefs.h:493
int * ExtToIntRowMap
Definition: spdefs.h:841
BOOLEAN Factored
Definition: spdefs.h:842
#define SCLR_MULT_ASSIGN(to, sclr)
Definition: spdefs.h:212
static char copyright[]
Definition: sputils.c:53
#define MIN(a, b)
Definition: grids.h:32
void spStripFills(char *eMatrix)
Definition: sputils.c:1140
RealNumber spPseudoCondition(char *eMatrix)
Definition: sputils.c:1361
int * IntToExtRowMap
Definition: spdefs.h:850
#define SWAP(type, a, b)
Definition: spdefs.h:140
register int Size
Definition: spoutput.c:570
void spScale(char *eMatrix, RealVector RHS_ScaleFactors, RealVector SolutionScaleFactors)
Definition: sputils.c:376
static void ScaleComplexMatrix()
static void ComplexTransposedMatrixMultiply()
spREAL RealNumber
Definition: spdefs.h:468
#define YES
Definition: spdefs.h:109
register int * pExtOrder
Definition: sputils.c:600
ElementPtr NextAvailFillin
Definition: spdefs.h:875
struct FillinListNodeStruct * FirstFillinListNode
Definition: spdefs.h:877
int Elements
Definition: spdefs.h:837
static void SwapCols()
register int I
Definition: sputils.c:600
int MaxRowCountInLowerTri
Definition: spdefs.h:854
ElementPtr spcFindElementInCol(MatrixPtr Matrix, ElementPtr *LastAddr, int Row, int Col, BOOLEAN CreateIfMissing)
Definition: spbuild.c:300
BOOLEAN Complex
Definition: spdefs.h:832
#define SQR(a)
Definition: spdefs.h:137
BOOLEAN Reordered
Definition: spdefs.h:863
struct MatrixFrame * MatrixPtr
Definition: spdefs.h:880
RealNumber spNorm(char *eMatrix)
Definition: sputils.c:1857
int FillinsRemaining
Definition: spdefs.h:876
static RealNumber ComplexCondition()
static char RCSid[]
Definition: sputils.c:55
struct MatrixElement * NextInCol
Definition: spdefs.h:556
static int CountTwins()
ElementPtr pPivot
Definition: spsolve.c:145
#define spNO_MEMORY
Definition: spmatrix.h:101
return NULL
Definition: cabcode.cpp:461
ASSERT(IS_SPARSE(Matrix) AND NOT Matrix->Factored)
void spcLinkRows(MatrixPtr)
Definition: spbuild.c:869
#define spZERO_DIAG
Definition: spmatrix.h:99
MatrixPtr Matrix
Definition: sputils.c:601
register RealVector Vector
Definition: sputils.c:596
int CurrentSize
Definition: spdefs.h:833
#define CMPLX_RECIPROCAL(to, den)
Definition: spdefs.h:352
void spcColExchange(MatrixPtr, int col1, int col2)
Definition: spfactor.c:2335