NEURON
sputils.cpp
Go to the documentation of this file.
1 /*
2  * MATRIX UTILITY MODULE
3  *
4  * Author: Advising professor:
5  * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli
6  * UC Berkeley
7  *
8  * This file contains various optional utility routines.
9  *
10  * >>> User accessible functions contained in this file:
11  * spMNA_Preorder
12  * spScale
13  * spMultiply
14  * spMultTransposed
15  * spDeterminant
16  * spStrip
17  * spDeleteRowAndCol
18  * spPseudoCondition
19  * spCondition
20  * spNorm
21  * spLargestElement
22  * spRoundoff
23  *
24  * >>> Other functions contained in this file:
25  * CountTwins
26  * SwapCols
27  */
28 
29 /*
30  * Revision and copyright information.
31  *
32  * Copyright (c) 1985,86,87,88
33  * by Kenneth S. Kundert and the University of California.
34  *
35  * Permission to use, copy, modify, and distribute this software and
36  * its documentation for any purpose and without fee is hereby granted,
37  * provided that the copyright notices appear in all copies and
38  * supporting documentation and that the authors and the University of
39  * California are properly credited. The authors and the University of
40  * California make no representations as to the suitability of this
41  * software for any purpose. It is provided `as is', without express
42  * or implied warranty.
43  */
44 
45 /*
46  * IMPORTS
47  *
48  * >>> Import descriptions:
49  * spconfig.h
50  * Macros that customize the sparse matrix routines.
51  * spmatrix.h
52  * Macros and declarations to be imported by the user.
53  * spdefs.h
54  * Matrix type and macro definitions for the sparse matrix routines.
55  */
56 
57 #define spINSIDE_SPARSE
58 #include "spconfig.h"
59 #include "spdefs.h"
60 #include "spmatrix.h"
61 #include <cfloat>
62 
63 extern void spcLinkRows(MatrixPtr);
64 extern void spcRowExchange(MatrixPtr, int row1, int row2);
65 extern void spcColExchange(MatrixPtr, int col1, int col2);
66 extern ElementPtr spcFindElementInCol(MatrixPtr Matrix, ElementPtr* LastAddr, int Row, int Col, BOOLEAN CreateIfMissing);
67 
68 /* avoid "declared implicitly `extern' and later `static' " warnings. */
69 static int CountTwins(MatrixPtr Matrix, int Col, ElementPtr* ppTwin1, ElementPtr* ppTwin2);
70 static void SwapCols(MatrixPtr Matrix, ElementPtr pTwin1, ElementPtr pTwin2);
71 
72 #if MODIFIED_NODAL
73 /*
74  * PREORDER MODIFIED NODE ADMITTANCE MATRIX TO REMOVE ZEROS FROM DIAGONAL
75  *
76  * This routine massages modified node admittance matrices to remove
77  * zeros from the diagonal. It takes advantage of the fact that the
78  * row and column associated with a zero diagonal usually have
79  * structural ones placed symmetricly. This routine should be used
80  * only on modified node admittance matrices and should be executed
81  * after the matrix has been built but before the factorization
82  * begins. It should be executed for the initial factorization only
83  * and should be executed before the rows have been linked. Thus it
84  * should be run before using spScale(), spMultiply(),
85  * spDeleteRowAndCol(), or spNorm().
86  *
87  * This routine exploits the fact that the structural ones are placed
88  * in the matrix in symmetric twins. For example, the stamps for
89  * grounded and a floating voltage sources are
90  * grounded: floating:
91  * [ x x 1 ] [ x x 1 ]
92  * [ x x ] [ x x -1 ]
93  * [ 1 ] [ 1 -1 ]
94  * Notice for the grounded source, there is one set of twins, and for
95  * the floating, there are two sets. We remove the zero from the diagonal
96  * by swapping the rows associated with a set of twins. For example:
97  * grounded: floating 1: floating 2:
98  * [ 1 ] [ 1 -1 ] [ x x 1 ]
99  * [ x x ] [ x x -1 ] [ 1 -1 ]
100  * [ x x 1 ] [ x x 1 ] [ x x -1 ]
101  *
102  * It is important to deal with any zero diagonals that only have one
103  * set of twins before dealing with those that have more than one because
104  * swapping row destroys the symmetry of any twins in the rows being
105  * swapped, which may limit future moves. Consider
106  * [ x x 1 ]
107  * [ x x -1 1 ]
108  * [ 1 -1 ]
109  * [ 1 ]
110  * There is one set of twins for diagonal 4 and two for diagonal 3.
111  * Dealing with diagonal 4 first requires swapping rows 2 and 4.
112  * [ x x 1 ]
113  * [ 1 ]
114  * [ 1 -1 ]
115  * [ x x -1 1 ]
116  * We can now deal with diagonal 3 by swapping rows 1 and 3.
117  * [ 1 -1 ]
118  * [ 1 ]
119  * [ x x 1 ]
120  * [ x x -1 1 ]
121  * And we are done, there are no zeros left on the diagonal. However, if
122  * we originally dealt with diagonal 3 first, we could swap rows 2 and 3
123  * [ x x 1 ]
124  * [ 1 -1 ]
125  * [ x x -1 1 ]
126  * [ 1 ]
127  * Diagonal 4 no longer has a symmetric twin and we cannot continue.
128  *
129  * So we always take care of lone twins first. When none remain, we
130  * choose arbitrarily a set of twins for a diagonal with more than one set
131  * and swap the rows corresponding to that twin. We then deal with any
132  * lone twins that were created and repeat the procedure until no
133  * zero diagonals with symmetric twins remain.
134  *
135  * In this particular implementation, columns are swapped rather than rows.
136  * The algorithm used in this function was developed by Ken Kundert and
137  * Tom Quarles.
138  *
139  * >>> Arguments:
140  * eMatrix <input> (char *)
141  * Pointer to the matrix to be preordered.
142  *
143  * >>> Local variables;
144  * J (int)
145  * Column with zero diagonal being currently considered.
146  * pTwin1 (ElementPtr)
147  * Pointer to the twin found in the column belonging to the zero diagonal.
148  * pTwin2 (ElementPtr)
149  * Pointer to the twin found in the row belonging to the zero diagonal.
150  * belonging to the zero diagonal.
151  * AnotherPassNeeded (BOOLEAN)
152  * Flag indicating that at least one zero diagonal with symmetric twins
153  * remain.
154  * StartAt (int)
155  * Column number of first zero diagonal with symmetric twins.
156  * Swapped (BOOLEAN)
157  * Flag indicating that columns were swapped on this pass.
158  * Twins (int)
159  * Number of symmetric twins corresponding to current zero diagonal.
160  */
161 
162 void spMNA_Preorder(char* eMatrix)
163 {
164  MatrixPtr Matrix = (MatrixPtr)eMatrix;
165  int J, Size;
166  ElementPtr pTwin1 = 0, pTwin2 = 0;
167  int Twins, StartAt = 1;
168  BOOLEAN Swapped, AnotherPassNeeded;
169 
170  /* Begin `spMNA_Preorder'. */
171  ASSERT(IS_VALID(Matrix) AND NOT Matrix->Factored);
172 
173  if (Matrix->RowsLinked)
174  return;
175  Size = Matrix->Size;
176  Matrix->Reordered = YES;
177 
178  do {
179  AnotherPassNeeded = Swapped = NO;
180 
181  /* Search for zero diagonals with lone twins. */
182  for (J = StartAt; J <= Size; J++) {
183  if (Matrix->Diag[J] == NULL) {
184  Twins = CountTwins(Matrix, J, &pTwin1, &pTwin2);
185  if (Twins == 1) { /* Lone twins found, swap rows. */
186  SwapCols(Matrix, pTwin1, pTwin2);
187  Swapped = YES;
188  } else if ((Twins > 1) AND NOT AnotherPassNeeded) {
189  AnotherPassNeeded = YES;
190  StartAt = J;
191  }
192  }
193  }
194 
195  /* All lone twins are gone, look for zero diagonals with multiple twins. */
196  if (AnotherPassNeeded) {
197  for (J = StartAt; NOT Swapped AND(J <= Size); J++) {
198  if (Matrix->Diag[J] == NULL) {
199  Twins = CountTwins(Matrix, J, &pTwin1, &pTwin2);
200  SwapCols(Matrix, pTwin1, pTwin2);
201  Swapped = YES;
202  }
203  }
204  }
205  } while (AnotherPassNeeded);
206  return;
207 }
208 
209 /*
210  * COUNT TWINS
211  *
212  * This function counts the number of symmetric twins associated with
213  * a zero diagonal and returns one set of twins if any exist. The
214  * count is terminated early at two.
215  */
216 
217 static int CountTwins(MatrixPtr Matrix, int Col, ElementPtr* ppTwin1, ElementPtr* ppTwin2)
218 {
219  int Row, Twins = 0;
220  ElementPtr pTwin1, pTwin2;
221 
222  /* Begin `CountTwins'. */
223 
224  pTwin1 = Matrix->FirstInCol[Col];
225  while (pTwin1 != NULL) {
226  if (ABS(pTwin1->Real) == 1.0) {
227  Row = pTwin1->Row;
228  pTwin2 = Matrix->FirstInCol[Row];
229  while ((pTwin2 != NULL) AND(pTwin2->Row != Col))
230  pTwin2 = pTwin2->NextInCol;
231  if ((pTwin2 != NULL) AND(ABS(pTwin2->Real) == 1.0)) { /* Found symmetric twins. */
232  if (++Twins >= 2)
233  return Twins;
234  (*ppTwin1 = pTwin1)->Col = Col;
235  (*ppTwin2 = pTwin2)->Col = Row;
236  }
237  }
238  pTwin1 = pTwin1->NextInCol;
239  }
240  return Twins;
241 }
242 
243 /*
244  * SWAP COLUMNS
245  *
246  * This function swaps two columns and is applicable before the rows are
247  * linked.
248  */
249 
250 static void SwapCols(MatrixPtr Matrix, ElementPtr pTwin1, ElementPtr pTwin2)
251 {
252  int Col1 = pTwin1->Col, Col2 = pTwin2->Col;
253 
254  /* Begin `SwapCols'. */
255 
256  SWAP(ElementPtr, Matrix->FirstInCol[Col1], Matrix->FirstInCol[Col2]);
257  SWAP(int, Matrix->IntToExtColMap[Col1], Matrix->IntToExtColMap[Col2]);
258 
259  Matrix->Diag[Col1] = pTwin2;
260  Matrix->Diag[Col2] = pTwin1;
261  Matrix->NumberOfInterchangesIsOdd = NOT Matrix->NumberOfInterchangesIsOdd;
262  return;
263 }
264 #endif /* MODIFIED_NODAL */
265 
266 #if SCALING
267 /*
268  * SCALE MATRIX
269  *
270  * This function scales the matrix to enhance the possibility of
271  * finding a good pivoting order. Note that scaling enhances accuracy
272  * of the solution only if it affects the pivoting order, so it makes
273  * no sense to scale the matrix before spFactor(). If scaling is
274  * desired it should be done before spOrderAndFactor(). There
275  * are several things to take into account when choosing the scale
276  * factors. First, the scale factors are directly multiplied against
277  * the elements in the matrix. To prevent roundoff, each scale factor
278  * should be equal to an integer power of the number base of the
279  * machine. Since most machines operate in base two, scale factors
280  * should be a power of two. Second, the matrix should be scaled such
281  * that the matrix of element uncertainties is equilibrated. Third,
282  * this function multiplies the scale factors by the elements, so if
283  * one row tends to have uncertainties 1000 times smaller than the
284  * other rows, then its scale factor should be 1024, not 1/1024.
285  * Fourth, to save time, this function does not scale rows or columns
286  * if their scale factors are equal to one. Thus, the scale factors
287  * should be normalized to the most common scale factor. Rows and
288  * columns should be normalized separately. For example, if the size
289  * of the matrix is 100 and 10 rows tend to have uncertainties near
290  * 1e-6 and the remaining 90 have uncertainties near 1e-12, then the
291  * scale factor for the 10 should be 1/1,048,576 and the scale factors
292  * for the remaining 90 should be 1. Fifth, since this routine
293  * directly operates on the matrix, it is necessary to apply the scale
294  * factors to the RHS and Solution vectors. It may be easier to
295  * simply use spOrderAndFactor() on a scaled matrix to choose the
296  * pivoting order, and then throw away the matrix. Subsequent
297  * factorizations, performed with spFactor(), will not need to have
298  * the RHS and Solution vectors descaled. Lastly, this function
299  * should not be executed before the function spMNA_Preorder.
300  *
301  * >>> Arguments:
302  * eMatrix <input> (char *)
303  * Pointer to the matrix to be scaled.
304  * SolutionScaleFactors <input> (RealVector)
305  * The array of Solution scale factors. These factors scale the columns.
306  * All scale factors are real valued.
307  * RHS_ScaleFactors <input> (RealVector)
308  * The array of RHS scale factors. These factors scale the rows.
309  * All scale factors are real valued.
310  *
311  * >>> Local variables:
312  * lSize (int)
313  * Local version of the size of the matrix.
314  * pElement (ElementPtr)
315  * Pointer to an element in the matrix.
316  * pExtOrder (int *)
317  * Pointer into either IntToExtRowMap or IntToExtColMap vector. Used to
318  * compensate for any row or column swaps that have been performed.
319  * ScaleFactor (RealNumber)
320  * The scale factor being used on the current row or column.
321  */
322 
323 void spScale(char* eMatrix, RealVector RHS_ScaleFactors, RealVector SolutionScaleFactors)
324 {
325  MatrixPtr Matrix = (MatrixPtr)eMatrix;
326  ElementPtr pElement;
327  int I, lSize, *pExtOrder;
328  RealNumber ScaleFactor;
329 
330  /* Begin `spScale'. */
331  ASSERT(IS_VALID(Matrix) AND NOT Matrix->Factored);
332  if (NOT Matrix->RowsLinked)
334 
335 #if REAL
336  lSize = Matrix->Size;
337 
338 /* Correct pointers to arrays for ARRAY_OFFSET */
339 #if NOT ARRAY_OFFSET
340  --RHS_ScaleFactors;
341  --SolutionScaleFactors;
342 #endif
343 
344  /* Scale Rows */
345  pExtOrder = &Matrix->IntToExtRowMap[1];
346  for (I = 1; I <= lSize; I++) {
347  if ((ScaleFactor = RHS_ScaleFactors[*(pExtOrder++)]) != 1.0) {
348  pElement = Matrix->FirstInRow[I];
349 
350  while (pElement != NULL) {
351  pElement->Real *= ScaleFactor;
352  pElement = pElement->NextInRow;
353  }
354  }
355  }
356 
357  /* Scale Columns */
358  pExtOrder = &Matrix->IntToExtColMap[1];
359  for (I = 1; I <= lSize; I++) {
360  if ((ScaleFactor = SolutionScaleFactors[*(pExtOrder++)]) != 1.0) {
361  pElement = Matrix->FirstInCol[I];
362 
363  while (pElement != NULL) {
364  pElement->Real *= ScaleFactor;
365  pElement = pElement->NextInCol;
366  }
367  }
368  }
369  return;
370 
371 #endif /* REAL */
372 }
373 #endif /* SCALING */
374 
375 
376 #if MULTIPLICATION
377 /*
378  * MATRIX MULTIPLICATION
379  *
380  * Multiplies matrix by solution vector to find source vector.
381  * Assumes matrix has not been factored. This routine can be used
382  * as a test to see if solutions are correct. It should not be used
383  * before spMNA_Preorder().
384  *
385  * >>> Arguments:
386  * eMatrix <input> (char *)
387  * Pointer to the matrix.
388  * RHS <output> (RealVector)
389  * RHS is the right hand side. This is what is being solved for.
390  * Solution <input> (RealVector)
391  * Solution is the vector being multiplied by the matrix.
392  * iRHS <optional output> (RealVector)
393  * iRHS is the imaginary portion of the right hand side. This is
394  * what is being solved for.
395  * iSolution <optional input> (RealVector)
396  * iSolution is the imaginary portion of the vector being multiplied
397  * by the matrix.
398  *
399  */
400 
401 void spMultiply(char* eMatrix, RealVector RHS, RealVector Solution, std::optional<RealVector> iRHS, std::optional<RealVector> iSolution)
402 {
403  ElementPtr pElement;
404  RealVector Vector;
405  RealNumber Sum;
406  int I, *pExtOrder;
407  MatrixPtr Matrix = (MatrixPtr)eMatrix;
408 
409  /* Begin `spMultiply'. */
410  ASSERT(IS_SPARSE(Matrix) AND NOT Matrix->Factored);
411  if (NOT Matrix->RowsLinked)
413 
414 #if REAL
415 #if NOT ARRAY_OFFSET
416  /* Correct array pointers for ARRAY_OFFSET. */
417  --RHS;
418  --Solution;
419 #endif
420 
421  /* Initialize Intermediate vector with reordered Solution vector. */
422  Vector = Matrix->Intermediate;
423  pExtOrder = &Matrix->IntToExtColMap[Matrix->Size];
424  for (I = Matrix->Size; I > 0; I--)
425  Vector[I] = Solution[*(pExtOrder--)];
426 
427  pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size];
428  for (I = Matrix->Size; I > 0; I--) {
429  pElement = Matrix->FirstInRow[I];
430  Sum = 0.0;
431 
432  while (pElement != NULL) {
433  Sum += pElement->Real * Vector[pElement->Col];
434  pElement = pElement->NextInRow;
435  }
436  RHS[*pExtOrder--] = Sum;
437  }
438  return;
439 #endif /* REAL */
440 }
441 #endif /* MULTIPLICATION */
442 
443 #if MULTIPLICATION AND TRANSPOSE
444 /*
445  * TRANSPOSED MATRIX MULTIPLICATION
446  *
447  * Multiplies transposed matrix by solution vector to find source vector.
448  * Assumes matrix has not been factored. This routine can be used
449  * as a test to see if solutions are correct. It should not be used
450  * before spMNA_Preorder().
451  *
452  * >>> Arguments:
453  * eMatrix <input> (char *)
454  * Pointer to the matrix.
455  * RHS <output> (RealVector)
456  * RHS is the right hand side. This is what is being solved for.
457  * Solution <input> (RealVector)
458  * Solution is the vector being multiplied by the matrix.
459  * iRHS <optional output> (RealVector)
460  * iRHS is the imaginary portion of the right hand side. This is
461  * what is being solved for.
462  * iSolution <optional input> (RealVector)
463  * iSolution is the imaginary portion of the vector being multiplied
464  * by the matrix.
465  *
466  */
467 
468 void spMultTransposed(char* eMatrix, RealVector RHS, RealVector Solution, std::optional<RealVector> iRHS, std::optional<RealVector> iSolution)
469 {
470  ElementPtr pElement;
471  RealVector Vector;
472  RealNumber Sum;
473  int I, *pExtOrder;
474  MatrixPtr Matrix = (MatrixPtr)eMatrix;
475 
476  /* Begin `spMultTransposed'. */
477  ASSERT(IS_SPARSE(Matrix) AND NOT Matrix->Factored);
478 
479 
480 #if REAL
481 #if NOT ARRAY_OFFSET
482  /* Correct array pointers for ARRAY_OFFSET. */
483  --RHS;
484  --Solution;
485 #endif
486 
487  /* Initialize Intermediate vector with reordered Solution vector. */
488  Vector = Matrix->Intermediate;
489  pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size];
490  for (I = Matrix->Size; I > 0; I--)
491  Vector[I] = Solution[*(pExtOrder--)];
492 
493  pExtOrder = &Matrix->IntToExtColMap[Matrix->Size];
494  for (I = Matrix->Size; I > 0; I--) {
495  pElement = Matrix->FirstInCol[I];
496  Sum = 0.0;
497 
498  while (pElement != NULL) {
499  Sum += pElement->Real * Vector[pElement->Row];
500  pElement = pElement->NextInCol;
501  }
502  RHS[*pExtOrder--] = Sum;
503  }
504  return;
505 #endif /* REAL */
506 }
507 #endif /* MULTIPLICATION AND TRANSPOSE */
508 
509 
510 #if DETERMINANT
511 /*
512  * CALCULATE DETERMINANT
513  *
514  * This routine in capable of calculating the determinant of the
515  * matrix once the LU factorization has been performed. Hence, only
516  * use this routine after spFactor() and before spClear().
517  * The determinant equals the product of all the diagonal elements of
518  * the lower triangular matrix L, except that this product may need
519  * negating. Whether the product or the negative product equals the
520  * determinant is determined by the number of row and column
521  * interchanges performed. Note that the determinants of matrices can
522  * be very large or very small. On large matrices, the determinant
523  * can be far larger or smaller than can be represented by a floating
524  * point number. For this reason the determinant is scaled to a
525  * reasonable value and the logarithm of the scale factor is returned.
526  *
527  * >>> Arguments:
528  * eMatrix <input> (char *)
529  * A pointer to the matrix for which the determinant is desired.
530  * pExponent <output> (int *)
531  * The logarithm base 10 of the scale factor for the determinant. To find
532  * the actual determinant, Exponent should be added to the exponent of
533  * Determinant.
534  * pDeterminant <output> (RealNumber *)
535  * The real portion of the determinant. This number is scaled to be
536  * greater than or equal to 1.0 and less than 10.0.
537  * piDeterminant <output> (RealNumber *)
538  * The imaginary portion of the determinant. When the matrix is real
539  * this pointer need not be supplied, nothing will be returned. This
540  * number is scaled to be greater than or equal to 1.0 and less than 10.0.
541  *
542  * >>> Local variables:
543  * Size (int)
544  * Local storage for Matrix->Size.
545  * Temp (RealNumber)
546  * Temporary storage for real portion of determinant.
547  */
548 
549 void spDeterminant(char* eMatrix, int* pExponent, RealNumber* pDeterminant, std::optional<RealNumber*> piDeterminant)
550 {
551  MatrixPtr Matrix = (MatrixPtr)eMatrix;
552  int I, Size;
553 
554  /* Begin `spDeterminant'. */
556  *pExponent = 0;
557 
558  if (Matrix->Error == spSINGULAR) {
559  *pDeterminant = 0.0;
560  return;
561  }
562 
563  Size = Matrix->Size;
564  I = 0;
565 
566 #if REAL
567  { /* Real Case. */
568  *pDeterminant = 1.0;
569 
570  while (++I <= Size) {
571  *pDeterminant /= Matrix->Diag[I]->Real;
572 
573  /* Scale Determinant. */
574  if (*pDeterminant != 0.0) {
575  while (ABS(*pDeterminant) >= 1.0e12) {
576  *pDeterminant *= 1.0e-12;
577  *pExponent += 12;
578  }
579  while (ABS(*pDeterminant) < 1.0e-12) {
580  *pDeterminant *= 1.0e12;
581  *pExponent -= 12;
582  }
583  }
584  }
585 
586  /* Scale Determinant again, this time to be between 1.0 <= x < 10.0. */
587  if (*pDeterminant != 0.0) {
588  while (ABS(*pDeterminant) >= 10.0) {
589  *pDeterminant *= 0.1;
590  (*pExponent)++;
591  }
592  while (ABS(*pDeterminant) < 1.0) {
593  *pDeterminant *= 10.0;
594  (*pExponent)--;
595  }
596  }
597  if (Matrix->NumberOfInterchangesIsOdd)
598  *pDeterminant = -*pDeterminant;
599  }
600 #endif /* REAL */
601 }
602 #endif /* DETERMINANT */
603 
604 #if STRIP
605 
606 /*
607  * STRIP FILL-INS FROM MATRIX
608  *
609  * Strips the matrix of all fill-ins.
610  *
611  * >>> Arguments:
612  * Matrix <input> (char *)
613  * Pointer to the matrix to be stripped.
614  *
615  * >>> Local variables:
616  * pElement (ElementPtr)
617  * Pointer that is used to step through the matrix.
618  * ppElement (ElementPtr *)
619  * Pointer to the location of an ElementPtr. This location will be
620  * updated if a fill-in is stripped from the matrix.
621  * pFillin (ElementPtr)
622  * Pointer used to step through the lists of fill-ins while marking them.
623  * pLastFillin (ElementPtr)
624  * A pointer to the last fill-in in the list. Used to terminate a loop.
625  * pListNode (struct FillinListNodeStruct *)
626  * A pointer to a node in the FillinList linked-list.
627  */
628 
629 void spStripFills(char* eMatrix)
630 {
631  MatrixPtr Matrix = (MatrixPtr)eMatrix;
632  struct FillinListNodeStruct* pListNode;
633 
634  /* Begin `spStripFills'. */
636  if (Matrix->Fillins == 0)
637  return;
638  Matrix->NeedsOrdering = YES;
639  Matrix->Elements -= Matrix->Fillins;
640  Matrix->Fillins = 0;
641 
642  /* Mark the fill-ins. */
643  {
644  ElementPtr pFillin, pLastFillin;
645 
646  pListNode = Matrix->LastFillinListNode = Matrix->FirstFillinListNode;
647  Matrix->FillinsRemaining = pListNode->NumberOfFillinsInList;
648  Matrix->NextAvailFillin = pListNode->pFillinList;
649 
650  while (pListNode != NULL) {
651  pFillin = pListNode->pFillinList;
652  pLastFillin = &(pFillin[pListNode->NumberOfFillinsInList - 1]);
653  while (pFillin <= pLastFillin)
654  (pFillin++)->Row = 0;
655  pListNode = pListNode->Next;
656  }
657  }
658 
659  /* Unlink fill-ins by searching for elements marked with Row = 0. */
660  {
661  ElementPtr pElement, *ppElement;
662  int I, Size = Matrix->Size;
663 
664  /* Unlink fill-ins in all columns. */
665  for (I = 1; I <= Size; I++) {
666  ppElement = &(Matrix->FirstInCol[I]);
667  while ((pElement = *ppElement) != NULL) {
668  if (pElement->Row == 0) {
669  *ppElement = pElement->NextInCol; /* Unlink fill-in. */
670  if (Matrix->Diag[pElement->Col] == pElement)
671  Matrix->Diag[pElement->Col] = NULL;
672  } else
673  ppElement = &pElement->NextInCol; /* Skip element. */
674  }
675  }
676 
677  /* Unlink fill-ins in all rows. */
678  for (I = 1; I <= Size; I++) {
679  ppElement = &(Matrix->FirstInRow[I]);
680  while ((pElement = *ppElement) != NULL) {
681  if (pElement->Row == 0)
682  *ppElement = pElement->NextInRow; /* Unlink fill-in. */
683  else
684  ppElement = &pElement->NextInRow; /* Skip element. */
685  }
686  }
687  }
688  return;
689 }
690 #endif
691 
692 #if PSEUDOCONDITION
693 /*
694  * CALCULATE PSEUDOCONDITION
695  *
696  * Computes the magnitude of the ratio of the largest to the smallest
697  * pivots. This quantity is an indicator of ill-conditioning in the
698  * matrix. If this ratio is large, and if the matrix is scaled such
699  * that uncertainties in the RHS and the matrix entries are
700  * equilibrated, then the matrix is ill-conditioned. However, a small
701  * ratio does not necessarily imply that the matrix is
702  * well-conditioned. This routine must only be used after a matrix has
703  * been factored by spOrderAndFactor() or spFactor() and before it is
704  * cleared by spClear() or spInitialize(). The pseudocondition is
705  * faster to compute than the condition number calculated by
706  * spCondition(), but is not as informative.
707  *
708  * >>> Returns:
709  * The magnitude of the ratio of the largest to smallest pivot used during
710  * previous factorization. If the matrix was singular, zero is returned.
711  *
712  * >>> Arguments:
713  * eMatrix <input> (char *)
714  * Pointer to the matrix.
715  */
716 
718 spPseudoCondition(char* eMatrix)
719 {
720  MatrixPtr Matrix = (MatrixPtr)eMatrix;
721  int I;
722  ArrayOfElementPtrs Diag;
723  RealNumber MaxPivot, MinPivot, Mag;
724 
725  /* Begin `spPseudoCondition'. */
726 
728  if (Matrix->Error == spSINGULAR OR Matrix->Error == spZERO_DIAG)
729  return 0.0;
730 
731  Diag = Matrix->Diag;
732  MaxPivot = MinPivot = ELEMENT_MAG(Diag[1]);
733  for (I = 2; I <= Matrix->Size; I++) {
734  Mag = ELEMENT_MAG(Diag[I]);
735  if (Mag > MaxPivot)
736  MaxPivot = Mag;
737  else if (Mag < MinPivot)
738  MinPivot = Mag;
739  }
740  ASSERT(MaxPivot > 0.0);
741  return MaxPivot / MinPivot;
742 }
743 #endif
744 
745 #if CONDITION
746 /*
747  * ESTIMATE CONDITION NUMBER
748  *
749  * Computes an estimate of the condition number using a variation on
750  * the LINPACK condition number estimation algorithm. This quantity is
751  * an indicator of ill-conditioning in the matrix. To avoid problems
752  * with overflow, the reciprocal of the condition number is returned.
753  * If this number is small, and if the matrix is scaled such that
754  * uncertainties in the RHS and the matrix entries are equilibrated,
755  * then the matrix is ill-conditioned. If the this number is near
756  * one, the matrix is well conditioned. This routine must only be
757  * used after a matrix has been factored by spOrderAndFactor() or
758  * spFactor() and before it is cleared by spClear() or spInitialize().
759  *
760  * Unlike the LINPACK condition number estimator, this routines
761  * returns the L infinity condition number. This is an artifact of
762  * Sparse placing ones on the diagonal of the upper triangular matrix
763  * rather than the lower. This difference should be of no importance.
764  *
765  * References:
766  * A.K. Cline, C.B. Moler, G.W. Stewart, J.H. Wilkinson. An estimate
767  * for the condition number of a matrix. SIAM Journal on Numerical
768  * Analysis. Vol. 16, No. 2, pages 368-375, April 1979.
769  *
770  * J.J. Dongarra, C.B. Moler, J.R. Bunch, G.W. Stewart. LINPACK
771  * User's Guide. SIAM, 1979.
772  *
773  * Roger G. Grimes, John G. Lewis. Condition number estimation for
774  * sparse matrices. SIAM Journal on Scientific and Statistical
775  * Computing. Vol. 2, No. 4, pages 384-388, December 1981.
776  *
777  * Dianne Prost O'Leary. Estimating matrix condition numbers. SIAM
778  * Journal on Scientific and Statistical Computing. Vol. 1, No. 2,
779  * pages 205-209, June 1980.
780  *
781  * >>> Returns:
782  * The reciprocal of the condition number. If the matrix was singular,
783  * zero is returned.
784  *
785  * >>> Arguments:
786  * eMatrix <input> (char *)
787  * Pointer to the matrix.
788  * NormOfMatrix <input> (RealNumber)
789  * The L-infinity norm of the unfactored matrix as computed by
790  * spNorm().
791  * pError <output> (int *)
792  * Used to return error code.
793  *
794  * >>> Possible errors:
795  * spSINGULAR
796  * spNO_MEMORY
797  */
798 
799 RealNumber spCondition(char* eMatrix, RealNumber NormOfMatrix, int* pError)
800 {
801  MatrixPtr Matrix = (MatrixPtr)eMatrix;
802  ElementPtr pElement;
803  RealVector T, Tm;
804  int I, K, Row;
805  ElementPtr pPivot;
806  int Size;
807  RealNumber E, Em, Wp, Wm, ASp, ASm, ASw, ASy, ASv, ASz, MaxY, ScaleFactor;
808  RealNumber Linpack, OLeary, InvNormOfInverse;
809 #define SLACK 1e4
810 
811  /* Begin `spCondition'. */
812 
814  *pError = Matrix->Error;
815  if (Matrix->Error >= spFATAL)
816  return 0.0;
817  if (NormOfMatrix == 0.0) {
818  *pError = spSINGULAR;
819  return 0.0;
820  }
821 
822 #if REAL
823  Size = Matrix->Size;
824  T = Matrix->Intermediate;
825  Tm = ALLOC(RealNumber, Size + 1);
826  if (Tm == NULL) {
827  *pError = spNO_MEMORY;
828  return 0.0;
829  }
830  for (I = Size; I > 0; I--)
831  T[I] = 0.0;
832 
833  /*
834  * Part 1. Ay = e.
835  * Solve Ay = LUy = e where e consists of +1 and -1 terms with the sign
836  * chosen to maximize the size of w in Lw = e. Since the terms in w can
837  * get very large, scaling is used to avoid overflow.
838  */
839 
840  /* Forward elimination. Solves Lw = e while choosing e. */
841  E = 1.0;
842  for (I = 1; I <= Size; I++) {
843  pPivot = Matrix->Diag[I];
844  if (T[I] < 0.0)
845  Em = -E;
846  else
847  Em = E;
848  Wm = (Em + T[I]) * pPivot->Real;
849  if (ABS(Wm) > SLACK) {
850  ScaleFactor = 1.0 / MAX(SQR(SLACK), ABS(Wm));
851  for (K = Size; K > 0; K--)
852  T[K] *= ScaleFactor;
853  E *= ScaleFactor;
854  Em *= ScaleFactor;
855  Wm = (Em + T[I]) * pPivot->Real;
856  }
857  Wp = (T[I] - Em) * pPivot->Real;
858  ASp = ABS(T[I] - Em);
859  ASm = ABS(Em + T[I]);
860 
861  /* Update T for both values of W, minus value is placed in Tm. */
862  pElement = pPivot->NextInCol;
863  while (pElement != NULL) {
864  Row = pElement->Row;
865  Tm[Row] = T[Row] - (Wm * pElement->Real);
866  T[Row] -= (Wp * pElement->Real);
867  ASp += ABS(T[Row]);
868  ASm += ABS(Tm[Row]);
869  pElement = pElement->NextInCol;
870  }
871 
872  /* If minus value causes more growth, overwrite T with its values. */
873  if (ASm > ASp) {
874  T[I] = Wm;
875  pElement = pPivot->NextInCol;
876  while (pElement != NULL) {
877  T[pElement->Row] = Tm[pElement->Row];
878  pElement = pElement->NextInCol;
879  }
880  } else
881  T[I] = Wp;
882  }
883 
884  /* Compute 1-norm of T, which now contains w, and scale ||T|| to 1/SLACK. */
885  for (ASw = 0.0, I = Size; I > 0; I--)
886  ASw += ABS(T[I]);
887  ScaleFactor = 1.0 / (SLACK * ASw);
888  if (ScaleFactor < 0.5) {
889  for (I = Size; I > 0; I--)
890  T[I] *= ScaleFactor;
891  E *= ScaleFactor;
892  }
893 
894  /* Backward Substitution. Solves Uy = w.*/
895  for (I = Size; I >= 1; I--) {
896  pElement = Matrix->Diag[I]->NextInRow;
897  while (pElement != NULL) {
898  T[I] -= pElement->Real * T[pElement->Col];
899  pElement = pElement->NextInRow;
900  }
901  if (ABS(T[I]) > SLACK) {
902  ScaleFactor = 1.0 / MAX(SQR(SLACK), ABS(T[I]));
903  for (K = Size; K > 0; K--)
904  T[K] *= ScaleFactor;
905  E *= ScaleFactor;
906  }
907  }
908 
909  /* Compute 1-norm of T, which now contains y, and scale ||T|| to 1/SLACK. */
910  for (ASy = 0.0, I = Size; I > 0; I--)
911  ASy += ABS(T[I]);
912  ScaleFactor = 1.0 / (SLACK * ASy);
913  if (ScaleFactor < 0.5) {
914  for (I = Size; I > 0; I--)
915  T[I] *= ScaleFactor;
916  ASy = 1.0 / SLACK;
917  E *= ScaleFactor;
918  }
919 
920  /* Compute infinity-norm of T for O'Leary's estimate. */
921  for (MaxY = 0.0, I = Size; I > 0; I--)
922  if (MaxY < ABS(T[I]))
923  MaxY = ABS(T[I]);
924 
925  /*
926  * Part 2. A* z = y where the * represents the transpose.
927  * Recall that A = LU implies A* = U* L*.
928  */
929 
930  /* Forward elimination, U* v = y. */
931  for (I = 1; I <= Size; I++) {
932  pElement = Matrix->Diag[I]->NextInRow;
933  while (pElement != NULL) {
934  T[pElement->Col] -= T[I] * pElement->Real;
935  pElement = pElement->NextInRow;
936  }
937  if (ABS(T[I]) > SLACK) {
938  ScaleFactor = 1.0 / MAX(SQR(SLACK), ABS(T[I]));
939  for (K = Size; K > 0; K--)
940  T[K] *= ScaleFactor;
941  ASy *= ScaleFactor;
942  }
943  }
944 
945  /* Compute 1-norm of T, which now contains v, and scale ||T|| to 1/SLACK. */
946  for (ASv = 0.0, I = Size; I > 0; I--)
947  ASv += ABS(T[I]);
948  ScaleFactor = 1.0 / (SLACK * ASv);
949  if (ScaleFactor < 0.5) {
950  for (I = Size; I > 0; I--)
951  T[I] *= ScaleFactor;
952  ASy *= ScaleFactor;
953  }
954 
955  /* Backward Substitution, L* z = v. */
956  for (I = Size; I >= 1; I--) {
957  pPivot = Matrix->Diag[I];
958  pElement = pPivot->NextInCol;
959  while (pElement != NULL) {
960  T[I] -= pElement->Real * T[pElement->Row];
961  pElement = pElement->NextInCol;
962  }
963  T[I] *= pPivot->Real;
964  if (ABS(T[I]) > SLACK) {
965  ScaleFactor = 1.0 / MAX(SQR(SLACK), ABS(T[I]));
966  for (K = Size; K > 0; K--)
967  T[K] *= ScaleFactor;
968  ASy *= ScaleFactor;
969  }
970  }
971 
972  /* Compute 1-norm of T, which now contains z. */
973  for (ASz = 0.0, I = Size; I > 0; I--)
974  ASz += ABS(T[I]);
975 
976  FREE(Tm);
977 
978  Linpack = ASy / ASz;
979  OLeary = E / MaxY;
980  InvNormOfInverse = MIN(Linpack, OLeary);
981  return InvNormOfInverse / NormOfMatrix;
982 #endif /* REAL */
983 }
984 
985 /*
986  * L-INFINITY MATRIX NORM
987  *
988  * Computes the L-infinity norm of an unfactored matrix. It is a fatal
989  * error to pass this routine a factored matrix.
990  *
991  * One difficulty is that the rows may not be linked.
992  *
993  * >>> Returns:
994  * The largest absolute row sum of matrix.
995  *
996  * >>> Arguments:
997  * eMatrix <input> (char *)
998  * Pointer to the matrix.
999  */
1000 
1001 RealNumber spNorm(char* eMatrix)
1002 {
1003  MatrixPtr Matrix = (MatrixPtr)eMatrix;
1004  ElementPtr pElement;
1005  int I;
1006  RealNumber Max = 0.0, AbsRowSum;
1007 
1008  /* Begin `spNorm'. */
1010  if (NOT Matrix->RowsLinked)
1012 
1013  /* Compute row sums. */
1014 #if REAL
1015  for (I = Matrix->Size; I > 0; I--) {
1016  pElement = Matrix->FirstInRow[I];
1017  AbsRowSum = 0.0;
1018  while (pElement != NULL) {
1019  AbsRowSum += ABS(pElement->Real);
1020  pElement = pElement->NextInRow;
1021  }
1022  if (Max < AbsRowSum)
1023  Max = AbsRowSum;
1024  }
1025 #endif
1026  return Max;
1027 }
1028 #endif /* CONDITION */
1029 
1030 #if STABILITY
1031 /*
1032  * STABILITY OF FACTORIZATION
1033  *
1034  * The following routines are used to gauge the stability of a
1035  * factorization. If the factorization is determined to be too unstable,
1036  * then the matrix should be reordered. The routines compute quantities
1037  * that are needed in the computation of a bound on the error attributed
1038  * to any one element in the matrix during the factorization. In other
1039  * words, there is a matrix E = [e_ij] of error terms such that A+E = LU.
1040  * This routine finds a bound on |e_ij|. Erisman & Reid [1] showed that
1041  * |e_ij| < 3.01 u rho m_ij, where u is the machine rounding unit,
1042  * rho = max a_ij where the max is taken over every row i, column j, and
1043  * step k, and m_ij is the number of multiplications required in the
1044  * computation of l_ij if i > j or u_ij otherwise. Barlow [2] showed that
1045  * rho < max_i || l_i ||_p max_j || u_j ||_q where 1/p + 1/q = 1.
1046  *
1047  * The first routine finds the magnitude on the largest element in the
1048  * matrix. If the matrix has not yet been factored, the largest
1049  * element is found by direct search. If the matrix is factored, a
1050  * bound on the largest element in any of the reduced submatrices is
1051  * computed using Barlow with p = oo and q = 1. The ratio of these
1052  * two numbers is the growth, which can be used to determine if the
1053  * pivoting order is adequate. A large growth implies that
1054  * considerable error has been made in the factorization and that it
1055  * is probably a good idea to reorder the matrix. If a large growth
1056  * in encountered after using spFactor(), reconstruct the matrix and
1057  * refactor using spOrderAndFactor(). If a large growth is
1058  * encountered after using spOrderAndFactor(), refactor using
1059  * spOrderAndFactor() with the pivot threshold increased, say to 0.1.
1060  *
1061  * Using only the size of the matrix as an upper bound on m_ij and
1062  * Barlow's bound, the user can estimate the size of the matrix error
1063  * terms e_ij using the bound of Erisman and Reid. The second routine
1064  * computes a tighter bound (with more work) based on work by Gear
1065  * [3], |e_ij| < 1.01 u rho (t c^3 + (1 + t)c^2) where t is the
1066  * threshold and c is the maximum number of off-diagonal elements in
1067  * any row of L. The expensive part of computing this bound is
1068  * determining the maximum number of off-diagonals in L, which changes
1069  * only when the order of the matrix changes. This number is computed
1070  * and saved, and only recomputed if the matrix is reordered.
1071  *
1072  * [1] A. M. Erisman, J. K. Reid. Monitoring the stability of the
1073  * triangular factorization of a sparse matrix. Numerische
1074  * Mathematik. Vol. 22, No. 3, 1974, pp 183-186.
1075  *
1076  * [2] J. L. Barlow. A note on monitoring the stability of triangular
1077  * decomposition of sparse matrices. "SIAM Journal of Scientific
1078  * and Statistical Computing." Vol. 7, No. 1, January 1986, pp 166-168.
1079  *
1080  * [3] I. S. Duff, A. M. Erisman, J. K. Reid. "Direct Methods for Sparse
1081  * Matrices." Oxford 1986. pp 99.
1082  */
1083 
1084 /*
1085  * LARGEST ELEMENT IN MATRIX
1086  *
1087  * >>> Returns:
1088  * If matrix is not factored, returns the magnitude of the largest element in
1089  * the matrix. If the matrix is factored, a bound on the magnitude of the
1090  * largest element in any of the reduced submatrices is returned.
1091  *
1092  * >>> Arguments:
1093  * eMatrix <input> (char *)
1094  * Pointer to the matrix.
1095  */
1096 
1098 {
1099  MatrixPtr Matrix = (MatrixPtr)eMatrix;
1100  int I;
1101  RealNumber Mag, AbsColSum, Max = 0.0, MaxRow = 0.0, MaxCol = 0.0;
1102  RealNumber Pivot;
1103  ElementPtr pElement, pDiag;
1104 
1105  /* Begin `spLargestElement'. */
1107 
1108 #if REAL
1109  if (Matrix->Factored) {
1110  if (Matrix->Error == spSINGULAR)
1111  return 0.0;
1112 
1113  /* Find the bound on the size of the largest element over all factorization. */
1114  for (I = 1; I <= Matrix->Size; I++) {
1115  pDiag = Matrix->Diag[I];
1116 
1117  /* Lower triangular matrix. */
1118  Pivot = 1.0 / pDiag->Real;
1119  Mag = ABS(Pivot);
1120  if (Mag > MaxRow)
1121  MaxRow = Mag;
1122  pElement = Matrix->FirstInRow[I];
1123  while (pElement != pDiag) {
1124  Mag = ABS(pElement->Real);
1125  if (Mag > MaxRow)
1126  MaxRow = Mag;
1127  pElement = pElement->NextInRow;
1128  }
1129 
1130  /* Upper triangular matrix. */
1131  pElement = Matrix->FirstInCol[I];
1132  AbsColSum = 1.0; /* Diagonal of U is unity. */
1133  while (pElement != pDiag) {
1134  AbsColSum += ABS(pElement->Real);
1135  pElement = pElement->NextInCol;
1136  }
1137  if (AbsColSum > MaxCol)
1138  MaxCol = AbsColSum;
1139  }
1140  } else {
1141  for (I = 1; I <= Matrix->Size; I++) {
1142  pElement = Matrix->FirstInCol[I];
1143  while (pElement != NULL) {
1144  Mag = ABS(pElement->Real);
1145  if (Mag > Max)
1146  Max = Mag;
1147  pElement = pElement->NextInCol;
1148  }
1149  }
1150  return Max;
1151  }
1152 #endif
1153  return MaxRow * MaxCol;
1154 }
1155 
1156 /*
1157  * MATRIX ROUNDOFF ERROR
1158  *
1159  * >>> Returns:
1160  * Returns a bound on the magnitude of the largest element in E = A - LU.
1161  *
1162  * >>> Arguments:
1163  * eMatrix <input> (char *)
1164  * Pointer to the matrix.
1165  * Rho <input> (RealNumber)
1166  * The bound on the magnitude of the largest element in any of the
1167  * reduced submatrices. This is the number computed by the function
1168  * spLargestElement() when given a factored matrix. If this number is
1169  * negative, the bound will be computed automatically.
1170  */
1171 
1172 RealNumber spRoundoff(char* eMatrix, RealNumber Rho)
1173 {
1174  MatrixPtr Matrix = (MatrixPtr)eMatrix;
1175  ElementPtr pElement;
1176  int Count, I, MaxCount = 0;
1177  RealNumber Reid, Gear;
1178 
1179  /* Begin `spRoundoff'. */
1181 
1182  /* Compute Barlow's bound if it is not given. */
1183  if (Rho < 0.0)
1184  Rho = spLargestElement(eMatrix);
1185 
1186  /* Find the maximum number of off-diagonals in L if not previously computed. */
1187  if (Matrix->MaxRowCountInLowerTri < 0) {
1188  for (I = Matrix->Size; I > 0; I--) {
1189  pElement = Matrix->FirstInRow[I];
1190  Count = 0;
1191  while (pElement->Col < I) {
1192  Count++;
1193  pElement = pElement->NextInRow;
1194  }
1195  if (Count > MaxCount)
1196  MaxCount = Count;
1197  }
1198  Matrix->MaxRowCountInLowerTri = MaxCount;
1199  } else
1200  MaxCount = Matrix->MaxRowCountInLowerTri;
1201 
1202  /* Compute error bound. */
1203  Gear = 1.01 * ((MaxCount + 1) * Matrix->RelThreshold + 1.0) * SQR(MaxCount);
1204  Reid = 3.01 * Matrix->Size;
1205 
1206  if (Gear < Reid)
1207  return (DBL_EPSILON * Rho * Gear);
1208  else
1209  return (DBL_EPSILON * Rho * Reid);
1210 }
1211 #endif
Definition: utility.h:81
#define MIN(a, b)
Definition: grids.h:32
#define MAX(a, b)
Definition: grids.h:31
#define RHS(i)
Definition: multisplit.cpp:57
if(ncell==0)
Definition: cellorder.cpp:785
#define NULL
Definition: spdefs.h:105
#define FREE(ptr)
Definition: spdefs.h:177
#define ALLOC(type, number)
Definition: spdefs.h:173
#define OR
Definition: spdefs.h:101
#define BOOLEAN
Definition: spdefs.h:96
#define SWAP(type, a, b)
Definition: spdefs.h:125
struct MatrixFrame * MatrixPtr
Definition: spdefs.h:549
spREAL RealNumber
Definition: spdefs.h:202
#define YES
Definition: spdefs.h:98
#define IS_VALID(matrix)
Definition: spdefs.h:110
#define IS_FACTORED(matrix)
Definition: spdefs.h:111
spREAL * RealVector
Definition: spdefs.h:202
#define NO
Definition: spdefs.h:97
#define ASSERT(condition)
Definition: spdefs.h:151
#define AND
Definition: spdefs.h:100
#define NOT
Definition: spdefs.h:99
#define SQR(a)
Definition: spdefs.h:122
#define ELEMENT_MAG(ptr)
Definition: spdefs.h:134
#define ABS(a)
Definition: spdefs.h:119
#define IS_SPARSE(matrix)
Definition: spdefs.h:109
#define spNO_MEMORY
Definition: spmatrix.h:90
#define spZERO_DIAG
Definition: spmatrix.h:88
#define spSINGULAR
Definition: spmatrix.h:89
#define spFATAL
Definition: spmatrix.h:93
void spcRowExchange(MatrixPtr, int row1, int row2)
Definition: spfactor.cpp:1797
ElementPtr spcFindElementInCol(MatrixPtr Matrix, ElementPtr *LastAddr, int Row, int Col, BOOLEAN CreateIfMissing)
Definition: spbuild.cpp:232
void spDeterminant(char *eMatrix, int *pExponent, RealNumber *pDeterminant, std::optional< RealNumber * > piDeterminant)
Definition: sputils.cpp:549
static void SwapCols(MatrixPtr Matrix, ElementPtr pTwin1, ElementPtr pTwin2)
Definition: sputils.cpp:250
RealNumber spCondition(char *eMatrix, RealNumber NormOfMatrix, int *pError)
Definition: sputils.cpp:799
static int CountTwins(MatrixPtr Matrix, int Col, ElementPtr *ppTwin1, ElementPtr *ppTwin2)
Definition: sputils.cpp:217
void spcColExchange(MatrixPtr, int col1, int col2)
Definition: spfactor.cpp:1880
void spMultTransposed(char *eMatrix, RealVector RHS, RealVector Solution, std::optional< RealVector > iRHS, std::optional< RealVector > iSolution)
Definition: sputils.cpp:468
void spScale(char *eMatrix, RealVector RHS_ScaleFactors, RealVector SolutionScaleFactors)
Definition: sputils.cpp:323
RealNumber spLargestElement(char *eMatrix)
Definition: sputils.cpp:1097
void spStripFills(char *eMatrix)
Definition: sputils.cpp:629
void spcLinkRows(MatrixPtr)
Definition: spbuild.cpp:608
void spMNA_Preorder(char *eMatrix)
Definition: sputils.cpp:162
RealNumber spRoundoff(char *eMatrix, RealNumber Rho)
Definition: sputils.cpp:1172
RealNumber spNorm(char *eMatrix)
Definition: sputils.cpp:1001
#define SLACK
RealNumber spPseudoCondition(char *eMatrix)
Definition: sputils.cpp:718
void spMultiply(char *eMatrix, RealVector RHS, RealVector Solution, std::optional< RealVector > iRHS, std::optional< RealVector > iSolution)
Definition: sputils.cpp:401
int NumberOfFillinsInList
Definition: spdefs.h:304
ElementPtr pFillinList
Definition: spdefs.h:303
struct FillinListNodeStruct * Next
Definition: spdefs.h:305
RealNumber Real
Definition: spdefs.h:245
struct MatrixElement * NextInCol
Definition: spdefs.h:249
struct MatrixElement * NextInRow
Definition: spdefs.h:248