Jspice3
spfactor.c
Go to the documentation of this file.
1 /*
2  * MATRIX FACTORIZATION MODULE
3  *
4  * Author: Advising Professor:
5  * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli
6  * UC Berkeley
7  *
8  * This file contains the routines to factor the matrix into LU form.
9  *
10  * >>> User accessible functions contained in this file:
11  * spOrderAndFactor
12  * spFactor
13  * spPartition
14  *
15  * >>> Other functions contained in this file:
16  * FactorComplexMatrix spcCreateInternalVectors
17  * CountMarkowitz MarkowitzProducts
18  * SearchForPivot SearchForSingleton
19  * QuicklySearchDiagonal SearchDiagonal
20  * SearchEntireMatrix FindLargestInCol
21  * FindBiggestInColExclude ExchangeRowsAndCols
22  * spcRowExchange spcColExchange
23  * ExchangeColElements ExchangeRowElements
24  * RealRowColElimination ComplexRowColElimination
25  * UpdateMarkowitzNumbers CreateFillin
26  * MatrixIsSingular ZeroPivot
27  * WriteStatus
28  */
29 
30 
31 /*
32  * Revision and copyright information.
33  *
34  * Copyright (c) 1985,86,87,88,89,90
35  * by Kenneth S. Kundert and the University of California.
36  *
37  * Permission to use, copy, modify, and distribute this software and
38  * its documentation for any purpose and without fee is hereby granted,
39  * provided that the copyright notices appear in all copies and
40  * supporting documentation and that the authors and the University of
41  * California are properly credited. The authors and the University of
42  * California make no representations as to the suitability of this
43  * software for any purpose. It is provided `as is', without express
44  * or implied warranty.
45  */
46 
47 #ifdef notused
48 static char copyright[] =
49  "Sparse1.3: Copyright (c) 1985,86,87,88,89,90 by Kenneth S. Kundert";
50 static char RCSid[] =
51  "@(#)$Header: spFactor.c,v 1.3 88/06/24 05:01:12 kundert Exp $";
52 #endif
53 
54 
55 
56 /*
57  * IMPORTS
58  *
59  * >>> Import descriptions:
60  * spConfig.h
61  * Macros that customize the sparse matrix routines.
62  * spMatrix.h
63  * Macros and declarations to be imported by the user.
64  * spDefs.h
65  * Matrix type and macro definitions for the sparse matrix routines.
66  */
67 
68 #define spINSIDE_SPARSE
69 #include "spconfig.h"
70 #include "spmatrix.h"
71 #include "spdefs.h"
72 
73 /*
74  * Function declarations
75  */
76 
77 #ifdef __STDC__
78 static int FactorComplexMatrix( MatrixPtr );
79 static void CountMarkowitz( MatrixPtr, RealVector, int );
80 static void MarkowitzProducts( MatrixPtr, int );
81 static ElementPtr SearchForPivot( MatrixPtr, int, int );
84 static ElementPtr SearchDiagonal( MatrixPtr, int );
88 static void ExchangeRowsAndCols( MatrixPtr, ElementPtr, int );
89 static void ExchangeColElements( MatrixPtr, int, ElementPtr, int,
90  ElementPtr, int );
91 static void ExchangeRowElements( MatrixPtr, int, ElementPtr, int,
92  ElementPtr, int );
96 static ElementPtr CreateFillin( MatrixPtr, int, int );
97 static int MatrixIsSingular( MatrixPtr, int );
98 static int ZeroPivot( MatrixPtr, int );
99 static void WriteStatus( MatrixPtr, int );
100 #else /* __STDC__ */
101 static int FactorComplexMatrix();
102 static void CountMarkowitz();
103 static void MarkowitzProducts();
104 static ElementPtr SearchForPivot();
107 static ElementPtr SearchDiagonal();
111 static void ExchangeRowsAndCols();
112 static void ExchangeColElements();
113 static void ExchangeRowElements();
114 static void RealRowColElimination();
115 static void ComplexRowColElimination();
116 static void UpdateMarkowitzNumbers();
117 static ElementPtr CreateFillin();
118 static int MatrixIsSingular();
119 static int ZeroPivot();
120 static void WriteStatus();
121 #endif /* __STDC__ */
122 
123 
124 
125 
126 
127 /*
128  * ORDER AND FACTOR MATRIX
129  *
130  * This routine chooses a pivot order for the matrix and factors it
131  * into LU form. It handles both the initial factorization and subsequent
132  * factorizations when a reordering is desired. This is handled in a manner
133  * that is transparent to the user. The routine uses a variation of
134  * Gauss's method where the pivots are associated with L and the
135  * diagonal terms of U are one.
136  *
137  * >>> Returned:
138  * The error code is returned. Possible errors are listed below.
139  *
140  * >>> Arguments:
141  * Matrix <input> (char *)
142  * Pointer to matrix.
143  * RHS <input> (RealVector)
144  * Representative right-hand side vector that is used to determine
145  * pivoting order when the right hand side vector is sparse. If
146  * RHS is a NULL pointer then the RHS vector is assumed to
147  * be full and it is not used when determining the pivoting
148  * order.
149  * RelThreshold <input> (RealNumber)
150  * This number determines what the pivot relative threshold will
151  * be. It should be between zero and one. If it is one then the
152  * pivoting method becomes complete pivoting, which is very slow
153  * and tends to fill up the matrix. If it is set close to zero
154  * the pivoting method becomes strict Markowitz with no
155  * threshold. The pivot threshold is used to eliminate pivot
156  * candidates that would cause excessive element growth if they
157  * were used. Element growth is the cause of roundoff error.
158  * Element growth occurs even in well-conditioned matrices.
159  * Setting the RelThreshold large will reduce element growth and
160  * roundoff error, but setting it too large will cause execution
161  * time to be excessive and will result in a large number of
162  * fill-ins. If this occurs, accuracy can actually be degraded
163  * because of the large number of operations required on the
164  * matrix due to the large number of fill-ins. A good value seems
165  * to be 0.001. The default is chosen by giving a value larger
166  * than one or less than or equal to zero. This value should be
167  * increased and the matrix resolved if growth is found to be
168  * excessive. Changing the pivot threshold does not improve
169  * performance on matrices where growth is low, as is often the
170  * case with ill-conditioned matrices. Once a valid threshold is
171  * given, it becomes the new default. The default value of
172  * RelThreshold was choosen for use with nearly diagonally
173  * dominant matrices such as node- and modified-node admittance
174  * matrices. For these matrices it is usually best to use
175  * diagonal pivoting. For matrices without a strong diagonal, it
176  * is usually best to use a larger threshold, such as 0.01 or
177  * 0.1.
178  * AbsThreshold <input> (RealNumber)
179  * The absolute magnitude an element must have to be considered
180  * as a pivot candidate, except as a last resort. This number
181  * should be set significantly smaller than the smallest diagonal
182  * element that is is expected to be placed in the matrix. If
183  * there is no reasonable prediction for the lower bound on these
184  * elements, then AbsThreshold should be set to zero.
185  * AbsThreshold is used to reduce the possibility of choosing as a
186  * pivot an element that has suffered heavy cancellation and as a
187  * result mainly consists of roundoff error. Once a valid
188  * threshold is given, it becomes the new default.
189  * DiagPivoting <input> (BOOLEAN)
190  * A flag indicating that pivot selection should be confined to the
191  * diagonal if possible. If DiagPivoting is nonzero and if
192  * DIAGONAL_PIVOTING is enabled pivots will be chosen only from
193  * the diagonal unless there are no diagonal elements that satisfy
194  * the threshold criteria. Otherwise, the entire reduced
195  * submatrix is searched when looking for a pivot. The diagonal
196  * pivoting in Sparse is efficient and well refined, while the
197  * off-diagonal pivoting is not. For symmetric and near symmetric
198  * matrices, it is best to use diagonal pivoting because it
199  * results in the best performance when reordering the matrix and
200  * when factoring the matrix without ordering. If there is a
201  * considerable amount of nonsymmetry in the matrix, then
202  * off-diagonal pivoting may result in a better equation ordering
203  * simply because there are more pivot candidates to choose from.
204  * A better ordering results in faster subsequent factorizations.
205  * However, the initial pivot selection process takes considerably
206  * longer for off-diagonal pivoting.
207  *
208  * >>> Local variables:
209  * pPivot (ElementPtr)
210  * Pointer to the element being used as a pivot.
211  * ReorderingRequired (BOOLEAN)
212  * Flag that indicates whether reordering is required.
213  *
214  * >>> Possible errors:
215  * spNO_MEMORY
216  * spSINGULAR
217  * spSMALL_PIVOT
218  * Error is cleared in this function.
219  */
220 
221 int
222 spOrderAndFactor( eMatrix, RHS, RelThreshold, AbsThreshold, DiagPivoting )
223 
224 char *eMatrix;
225 RealNumber RHS[], RelThreshold, AbsThreshold;
226 BOOLEAN DiagPivoting;
227 {
228 MatrixPtr Matrix = (MatrixPtr)eMatrix;
230 int Step, Size, ReorderingRequired;
232 RealNumber LargestInCol, FindLargestInCol();
233 
234 /* Begin `spOrderAndFactor'. */
235  ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored);
236 
237  Matrix->Error = spOKAY;
238  Size = Matrix->Size;
239  if (RelThreshold <= 0.0) RelThreshold = Matrix->RelThreshold;
240  if (RelThreshold > 1.0) RelThreshold = Matrix->RelThreshold;
241  Matrix->RelThreshold = RelThreshold;
242  if (AbsThreshold < 0.0) AbsThreshold = Matrix->AbsThreshold;
243  Matrix->AbsThreshold = AbsThreshold;
244  ReorderingRequired = NO;
245 
246  if (NOT Matrix->NeedsOrdering)
247  {
248 /* Matrix has been factored before and reordering is not required. */
249  for (Step = 1; Step <= Size; Step++)
250  { pPivot = Matrix->Diag[Step];
251  LargestInCol = FindLargestInCol(Matrix,pPivot->NextInCol);
252  if ((LargestInCol * RelThreshold < ELEMENT_MAG(pPivot)))
253  { if (Matrix->Complex)
254  ComplexRowColElimination( Matrix, pPivot );
255  else
256  RealRowColElimination( Matrix, pPivot );
257  }
258  else
259  { ReorderingRequired = YES;
260  break; /* for loop */
261  }
262  }
263  if (NOT ReorderingRequired)
264  goto Done;
265  else
266  {
267 /*
268  * A pivot was not large enough to maintain accuracy,
269  * so a partial reordering is required.
270  */
271 
272 #if (ANNOTATE >= ON_STRANGE_BEHAVIOR)
273  printf("Reordering, Step = %1d\n", Step);
274 #endif
275  }
276  } /* End of if(NOT Matrix->NeedsOrdering) */
277  else
278  {
279 /*
280  * This is the first time the matrix has been factored. These few statements
281  * indicate to the rest of the code that a full reodering is required rather
282  * than a partial reordering, which occurs during a failure of a fast
283  * factorization.
284  */
285  Step = 1;
286  if (NOT Matrix->RowsLinked)
287  spcLinkRows( Matrix );
288  if (NOT Matrix->InternalVectorsAllocated)
289  spcCreateInternalVectors( Matrix );
290  if (Matrix->Error >= spFATAL)
291  return Matrix->Error;
292  }
293 
294 /* Form initial Markowitz products. */
295  CountMarkowitz( Matrix, RHS, Step );
296  MarkowitzProducts( Matrix, Step );
297  Matrix->MaxRowCountInLowerTri = -1;
298 
299 /* Perform reordering and factorization. */
300  for (; Step <= Size; Step++)
301  { pPivot = SearchForPivot( Matrix, Step, DiagPivoting );
302  if (pPivot == NULL) return MatrixIsSingular( Matrix, Step );
303  ExchangeRowsAndCols( Matrix, pPivot, Step );
304 
305  if (Matrix->Complex)
306  ComplexRowColElimination( Matrix, pPivot );
307  else
308  RealRowColElimination( Matrix, pPivot );
309 
310  if (Matrix->Error >= spFATAL) return Matrix->Error;
311  UpdateMarkowitzNumbers( Matrix, pPivot );
312 
313 #if (ANNOTATE == FULL)
314  WriteStatus( Matrix, Step );
315 #endif
316  }
317 
318 Done:
319  Matrix->NeedsOrdering = NO;
320  Matrix->Reordered = YES;
321  Matrix->Factored = YES;
322 
323  return Matrix->Error;
324 }
325 
326 
327 
328 
329 
330 
331 
332 /*
333  * FACTOR MATRIX
334  *
335  * This routine is the companion routine to spOrderAndFactor().
336  * Unlike spOrderAndFactor(), spFactor() cannot change the ordering.
337  * It is also faster than spOrderAndFactor(). The standard way of
338  * using these two routines is to first use spOrderAndFactor() for the
339  * initial factorization. For subsequent factorizations, spFactor()
340  * is used if there is some assurance that little growth will occur
341  * (say for example, that the matrix is diagonally dominant). If
342  * spFactor() is called for the initial factorization of the matrix,
343  * then spOrderAndFactor() is automatically called with the default
344  * threshold. This routine uses "row at a time" LU factorization.
345  * Pivots are associated with the lower triangular matrix and the
346  * diagonals of the upper triangular matrix are ones.
347  *
348  * >>> Returned:
349  * The error code is returned. Possible errors are listed below.
350  *
351  * >>> Arguments:
352  * Matrix <input> (char *)
353  * Pointer to matrix.
354  *
355  * >>> Possible errors:
356  * spNO_MEMORY
357  * spSINGULAR
358  * spZERO_DIAG
359  * spSMALL_PIVOT
360  * Error is cleared in this function.
361  */
362 
363 int
364 spFactor( eMatrix )
365 
366 char *eMatrix;
367 {
368 MatrixPtr Matrix = (MatrixPtr)eMatrix;
369 register ElementPtr pElement;
370 register ElementPtr pColumn;
371 register int Step, Size;
372 RealNumber Mult;
373 
374 /* Begin `spFactor'. */
375  ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored);
376 
377  if (Matrix->NeedsOrdering)
378  { return spOrderAndFactor( eMatrix, (RealVector)NULL,
379  0.0, 0.0, DIAG_PIVOTING_AS_DEFAULT );
380  }
381  if (NOT Matrix->Partitioned) spPartition( eMatrix, spDEFAULT_PARTITION );
382 #if spCOMPLEX
383  if (Matrix->Complex) return FactorComplexMatrix( Matrix );
384 #endif
385 
386 #if REAL
387  Size = Matrix->Size;
388 
389  if (Matrix->Diag[1]->Real == 0.0) return ZeroPivot( Matrix, 1 );
390  Matrix->Diag[1]->Real = 1.0 / Matrix->Diag[1]->Real;
391 
392 /* Start factorization. */
393  for (Step = 2; Step <= Size; Step++)
394  { if (Matrix->DoRealDirect[Step])
395  { /* Update column using direct addressing scatter-gather. */
396  register RealNumber *Dest = (RealNumber *)Matrix->Intermediate;
397 
398 /* Scatter. */
399  pElement = Matrix->FirstInCol[Step];
400  while (pElement != NULL)
401  { Dest[pElement->Row] = pElement->Real;
402  pElement = pElement->NextInCol;
403  }
404 
405 /* Update column. */
406  pColumn = Matrix->FirstInCol[Step];
407  while (pColumn->Row < Step)
408  { pElement = Matrix->Diag[pColumn->Row];
409  pColumn->Real = Dest[pColumn->Row] * pElement->Real;
410  while ((pElement = pElement->NextInCol) != NULL)
411  Dest[pElement->Row] -= pColumn->Real * pElement->Real;
412  pColumn = pColumn->NextInCol;
413  }
414 
415 /* Gather. */
416  pElement = Matrix->Diag[Step]->NextInCol;
417  while (pElement != NULL)
418  { pElement->Real = Dest[pElement->Row];
419  pElement = pElement->NextInCol;
420  }
421 
422 /* Check for singular matrix. */
423  if (Dest[Step] == 0.0) return ZeroPivot( Matrix, Step );
424  Matrix->Diag[Step]->Real = 1.0 / Dest[Step];
425  }
426  else
427  { /* Update column using indirect addressing scatter-gather. */
428  register RealNumber **pDest = (RealNumber **)Matrix->Intermediate;
429 
430 /* Scatter. */
431  pElement = Matrix->FirstInCol[Step];
432  while (pElement != NULL)
433  { pDest[pElement->Row] = &pElement->Real;
434  pElement = pElement->NextInCol;
435  }
436 
437 /* Update column. */
438  pColumn = Matrix->FirstInCol[Step];
439  while (pColumn->Row < Step)
440  { pElement = Matrix->Diag[pColumn->Row];
441  Mult = (*pDest[pColumn->Row] *= pElement->Real);
442  while ((pElement = pElement->NextInCol) != NULL)
443  *pDest[pElement->Row] -= Mult * pElement->Real;
444  pColumn = pColumn->NextInCol;
445  }
446 
447 /* Check for singular matrix. */
448  if (Matrix->Diag[Step]->Real == 0.0)
449  return ZeroPivot( Matrix, Step );
450  Matrix->Diag[Step]->Real = 1.0 / Matrix->Diag[Step]->Real;
451  }
452  }
453 
454  Matrix->Factored = YES;
455  return (Matrix->Error = spOKAY);
456 #endif /* REAL */
457 }
458 
459 
460 
461 
462 
463 
464 #if spCOMPLEX
465 /*
466  * FACTOR COMPLEX MATRIX
467  *
468  * This routine is the companion routine to spFactor(), it
469  * handles complex matrices. It is otherwise identical.
470  *
471  * >>> Returned:
472  * The error code is returned. Possible errors are listed below.
473  *
474  * >>> Arguments:
475  * Matrix <input> (char *)
476  * Pointer to matrix.
477  *
478  * >>> Possible errors:
479  * spSINGULAR
480  * Error is cleared in this function.
481  */
482 
483 static int
484 FactorComplexMatrix( Matrix )
485 
486 MatrixPtr Matrix;
487 {
488 register ElementPtr pElement;
489 register ElementPtr pColumn;
490 register int Step, Size;
491 ComplexNumber Mult, Pivot;
492 
493 /* Begin `FactorComplexMatrix'. */
494  ASSERT(Matrix->Complex);
495 
496  Size = Matrix->Size;
497  pElement = Matrix->Diag[1];
498  if (ELEMENT_MAG(pElement) == 0.0) return ZeroPivot( Matrix, 1 );
499 /* Cmplx expr: *pPivot = 1.0 / *pPivot. */
500  CMPLX_RECIPROCAL( *pElement, *pElement );
501 
502 /* Start factorization. */
503  for (Step = 2; Step <= Size; Step++)
504  { if (Matrix->DoCmplxDirect[Step])
505  { /* Update column using direct addressing scatter-gather. */
506  register ComplexNumber *Dest;
507  Dest = (ComplexNumber *)Matrix->Intermediate;
508 
509 /* Scatter. */
510  pElement = Matrix->FirstInCol[Step];
511  while (pElement != NULL)
512  { Dest[pElement->Row] = *(ComplexNumber *)pElement;
513  pElement = pElement->NextInCol;
514  }
515 
516 /* Update column. */
517  pColumn = Matrix->FirstInCol[Step];
518  while (pColumn->Row < Step)
519  { pElement = Matrix->Diag[pColumn->Row];
520  /* Cmplx expr: Mult = Dest[pColumn->Row] * (1.0 / *pPivot). */
521  CMPLX_MULT(Mult, Dest[pColumn->Row], *pElement);
522  CMPLX_ASSIGN(*pColumn, Mult);
523  while ((pElement = pElement->NextInCol) != NULL)
524  { /* Cmplx expr: Dest[pElement->Row] -= Mult * pElement */
525  CMPLX_MULT_SUBT_ASSIGN(Dest[pElement->Row],Mult,*pElement);
526  }
527  pColumn = pColumn->NextInCol;
528  }
529 
530 /* Gather. */
531  pElement = Matrix->Diag[Step]->NextInCol;
532  while (pElement != NULL)
533  { *(ComplexNumber *)pElement = Dest[pElement->Row];
534  pElement = pElement->NextInCol;
535  }
536 
537 /* Check for singular matrix. */
538  Pivot = Dest[Step];
539  if (CMPLX_1_NORM(Pivot) == 0.0) return ZeroPivot( Matrix, Step );
540  CMPLX_RECIPROCAL( *Matrix->Diag[Step], Pivot );
541  }
542  else
543  { /* Update column using direct addressing scatter-gather. */
544  register ComplexNumber **pDest;
545  pDest = (ComplexNumber **)Matrix->Intermediate;
546 
547 /* Scatter. */
548  pElement = Matrix->FirstInCol[Step];
549  while (pElement != NULL)
550  { pDest[pElement->Row] = (ComplexNumber *)pElement;
551  pElement = pElement->NextInCol;
552  }
553 
554 /* Update column. */
555  pColumn = Matrix->FirstInCol[Step];
556  while (pColumn->Row < Step)
557  { pElement = Matrix->Diag[pColumn->Row];
558  /* Cmplx expr: Mult = *pDest[pColumn->Row] * (1.0 / *pPivot). */
559  CMPLX_MULT(Mult, *pDest[pColumn->Row], *pElement);
560  CMPLX_ASSIGN(*pDest[pColumn->Row], Mult);
561  while ((pElement = pElement->NextInCol) != NULL)
562  { /* Cmplx expr: *pDest[pElement->Row] -= Mult * pElement */
563  CMPLX_MULT_SUBT_ASSIGN(*pDest[pElement->Row],Mult,*pElement);
564  }
565  pColumn = pColumn->NextInCol;
566  }
567 
568 /* Check for singular matrix. */
569  pElement = Matrix->Diag[Step];
570  if (ELEMENT_MAG(pElement) == 0.0) return ZeroPivot( Matrix, Step );
571  CMPLX_RECIPROCAL( *pElement, *pElement );
572  }
573  }
574 
575  Matrix->Factored = YES;
576  return (Matrix->Error = spOKAY);
577 }
578 #endif /* spCOMPLEX */
579 
580 
581 
582 
583 
584 
585 /*
586  * PARTITION MATRIX
587  *
588  * This routine determines the cost to factor each row using both
589  * direct and indirect addressing and decides, on a row-by-row basis,
590  * which addressing mode is fastest. This information is used in
591  * spFactor() to speed the factorization.
592  *
593  * When factoring a previously ordered matrix using spFactor(), Sparse
594  * operates on a row-at-a-time basis. For speed, on each step, the
595  * row being updated is copied into a full vector and the operations
596  * are performed on that vector. This can be done one of two ways,
597  * either using direct addressing or indirect addressing. Direct
598  * addressing is fastest when the matrix is relatively dense and
599  * indirect addressing is best when the matrix is quite sparse. The
600  * user selects the type of partition used with Mode. If Mode is set
601  * to spDIRECT_PARTITION, then the all rows are placed in the direct
602  * addressing partition. Similarly, if Mode is set to
603  * spINDIRECT_PARTITION, then the all rows are placed in the indirect
604  * addressing partition. By setting Mode to spAUTO_PARTITION, the
605  * user allows Sparse to select the partition for each row
606  * individually. spFactor() generally runs faster if Sparse is
607  * allowed to choose its own partitioning, however choosing a
608  * partition is expensive. The time required to choose a partition is
609  * of the same order of the cost to factor the matrix. If you plan to
610  * factor a large number of matrices with the same structure, it is
611  * best to let Sparse choose the partition. Otherwise, you should
612  * choose the partition based on the predicted density of the matrix.
613  *
614  * >>> Arguments:
615  * Matrix <input> (char *)
616  * Pointer to matrix.
617  * Mode <input> (int)
618  * Mode must be one of three special codes: spDIRECT_PARTITION,
619  * spINDIRECT_PARTITION, or spAUTO_PARTITION.
620  */
621 
622 void
623 spPartition( eMatrix, Mode )
624 
625 char *eMatrix;
626 int Mode;
627 {
628 MatrixPtr Matrix = (MatrixPtr)eMatrix;
629 register ElementPtr pElement, pColumn;
630 register int Step, Size;
631 register int *Nc, *No, *Nm;
632 BOOLEAN *DoRealDirect, *DoCmplxDirect;
633 
634 /* Begin `spPartition'. */
635  ASSERT( IS_SPARSE( Matrix ) );
636  if (Matrix->Partitioned) return;
637  Size = Matrix->Size;
638  DoRealDirect = Matrix->DoRealDirect;
639  DoCmplxDirect = Matrix->DoCmplxDirect;
640  Matrix->Partitioned = YES;
641 
642 /* If partition is specified by the user, this is easy. */
643  if (Mode == spDEFAULT_PARTITION) Mode = DEFAULT_PARTITION;
644  if (Mode == spDIRECT_PARTITION)
645  { for (Step = 1; Step <= Size; Step++)
646 #if REAL
647  DoRealDirect[Step] = YES;
648 #endif
649 #if spCOMPLEX
650  DoCmplxDirect[Step] = YES;
651 #endif
652  return;
653  }
654  else if (Mode == spINDIRECT_PARTITION)
655  { for (Step = 1; Step <= Size; Step++)
656 #if REAL
657  DoRealDirect[Step] = NO;
658 #endif
659 #if spCOMPLEX
660  DoCmplxDirect[Step] = NO;
661 #endif
662  return;
663  }
664  else ASSERT( Mode == spAUTO_PARTITION );
665 
666 /* Otherwise, count all operations needed in when factoring matrix. */
667  Nc = (int *)Matrix->MarkowitzRow;
668  No = (int *)Matrix->MarkowitzCol;
669  Nm = (int *)Matrix->MarkowitzProd;
670 
671 /* Start mock-factorization. */
672  for (Step = 1; Step <= Size; Step++)
673  { Nc[Step] = No[Step] = Nm[Step] = 0;
674 
675  pElement = Matrix->FirstInCol[Step];
676  while (pElement != NULL)
677  { Nc[Step]++;
678  pElement = pElement->NextInCol;
679  }
680 
681  pColumn = Matrix->FirstInCol[Step];
682  while (pColumn->Row < Step)
683  { pElement = Matrix->Diag[pColumn->Row];
684  Nm[Step]++;
685  while ((pElement = pElement->NextInCol) != NULL)
686  No[Step]++;
687  pColumn = pColumn->NextInCol;
688  }
689  }
690 
691  for (Step = 1; Step <= Size; Step++)
692  {
693 /*
694  * The following are just estimates based on a count on the number of
695  * machine instructions used on each machine to perform the various
696  * tasks. It was assumed that each machine instruction required the
697  * same amount of time (I don't believe this is true for the VAX, and
698  * have no idea if this is true for the 68000 family). For optimum
699  * performance, these numbers should be tuned to the machine.
700  * Nc is the number of nonzero elements in the column.
701  * Nm is the number of multipliers in the column.
702  * No is the number of operations in the inner loop.
703  */
704 
705 #define generic
706 #ifdef hp9000s300
707 #if REAL
708  DoRealDirect[Step] = (Nm[Step] + No[Step] > 3*Nc[Step] - 2*Nm[Step]);
709 #endif
710 #if spCOMPLEX
711  /* On the hp350, it is never profitable to use direct for complex. */
712  DoCmplxDirect[Step] = NO;
713 #endif
714 #undef generic
715 #endif
716 
717 #ifdef vax
718 #if REAL
719  DoRealDirect[Step] = (Nm[Step] + No[Step] > 3*Nc[Step] - 2*Nm[Step]);
720 #endif
721 #if spCOMPLEX
722  DoCmplxDirect[Step] = (Nm[Step] + No[Step] > 7*Nc[Step] - 4*Nm[Step]);
723 #endif
724 #undef generic
725 #endif
726 
727 #ifdef generic
728 #if REAL
729  DoRealDirect[Step] = (Nm[Step] + No[Step] > 3*Nc[Step] - 2*Nm[Step]);
730 #endif
731 #if spCOMPLEX
732  DoCmplxDirect[Step] = (Nm[Step] + No[Step] > 7*Nc[Step] - 4*Nm[Step]);
733 #endif
734 #undef generic
735 #endif
736  }
737 
738 #if (ANNOTATE == FULL)
739  { int Ops = 0;
740  for (Step = 1; Step <= Size; Step++)
741  Ops += No[Step];
742  printf("Operation count for inner loop of factorization = %d.\n", Ops);
743  }
744 #endif
745  return;
746 }
747 
748 
749 
750 
751 
752 
753 
754 /*
755  * CREATE INTERNAL VECTORS
756  *
757  * Creates the Markowitz and Intermediate vectors.
758  *
759  * >>> Arguments:
760  * Matrix <input> (MatrixPtr)
761  * Pointer to matrix.
762  *
763  * >>> Local variables:
764  * SizePlusOne (unsigned)
765  * Size of the arrays to be allocated.
766  *
767  * >>> Possible errors:
768  * spNO_MEMORY
769  */
770 
771 void
773 
774 MatrixPtr Matrix;
775 {
776 int Size;
777 
778 /* Begin `spcCreateInternalVectors'. */
779 /* Create Markowitz arrays. */
780  Size= Matrix->Size;
781 
782  if (Matrix->MarkowitzRow == NULL)
783  { if (( Matrix->MarkowitzRow = ALLOC(int, Size+1)) == NULL)
784  Matrix->Error = spNO_MEMORY;
785  }
786  if (Matrix->MarkowitzCol == NULL)
787  { if (( Matrix->MarkowitzCol = ALLOC(int, Size+1)) == NULL)
788  Matrix->Error = spNO_MEMORY;
789  }
790  if (Matrix->MarkowitzProd == NULL)
791  { if (( Matrix->MarkowitzProd = ALLOC(long, Size+2)) == NULL)
792  Matrix->Error = spNO_MEMORY;
793  }
794 
795 /* Create DoDirect vectors for use in spFactor(). */
796 #if REAL
797  if (Matrix->DoRealDirect == NULL)
798  { if (( Matrix->DoRealDirect = ALLOC(BOOLEAN, Size+1)) == NULL)
799  Matrix->Error = spNO_MEMORY;
800  }
801 #endif
802 #if spCOMPLEX
803  if (Matrix->DoCmplxDirect == NULL)
804  { if (( Matrix->DoCmplxDirect = ALLOC(BOOLEAN, Size+1)) == NULL)
805  Matrix->Error = spNO_MEMORY;
806  }
807 #endif
808 
809 /* Create Intermediate vectors for use in MatrixSolve. */
810 #if spCOMPLEX
811  if (Matrix->Intermediate == NULL)
812  { if ((Matrix->Intermediate = ALLOC(RealNumber,2*(Size+1))) == NULL)
813  Matrix->Error = spNO_MEMORY;
814  }
815 #else
816  if (Matrix->Intermediate == NULL)
817  { if ((Matrix->Intermediate = ALLOC(RealNumber, Size+1)) == NULL)
818  Matrix->Error = spNO_MEMORY;
819  }
820 #endif
821 
822  if (Matrix->Error != spNO_MEMORY)
823  Matrix->InternalVectorsAllocated = YES;
824  return;
825 }
826 
827 
828 
829 
830 
831 
832 
833 /*
834  * COUNT MARKOWITZ
835  *
836  * Scans Matrix to determine the Markowitz counts for each row and column.
837  *
838  * >>> Arguments:
839  * Matrix <input> (MatrixPtr)
840  * Pointer to matrix.
841  * RHS <input> (RealVector)
842  * Representative right-hand side vector that is used to determine
843  * pivoting order when the right hand side vector is sparse. If
844  * RHS is a NULL pointer then the RHS vector is assumed to be full
845  * and it is not used when determining the pivoting order.
846  * Step <input> (int)
847  * Index of the diagonal currently being eliminated.
848  *
849  * >>> Local variables:
850  * Count (int)
851  * Temporary counting variable.
852  * ExtRow (int)
853  * The external row number that corresponds to I.
854  * pElement (ElementPtr)
855  * Pointer to matrix elements.
856  * Size (int)
857  * The size of the matrix.
858  */
859 
860 static void
861 CountMarkowitz( Matrix, RHS, Step )
862 
863 MatrixPtr Matrix;
864 register RealVector RHS;
865 int Step;
866 {
867 register int Count, I, Size = Matrix->Size;
868 register ElementPtr pElement;
869 int ExtRow;
870 
871 /* Begin `CountMarkowitz'. */
872 
873 /* Correct array pointer for ARRAY_OFFSET. */
874 #if NOT ARRAY_OFFSET
875 #if spSEPARATED_COMPLEX_VECTORS OR NOT spCOMPLEX
876  if (RHS != NULL) --RHS;
877 #else
878  if (RHS != NULL)
879  { if (Matrix->Complex) RHS -= 2;
880  else --RHS;
881  }
882 #endif
883 #endif
884 
885 /* Generate MarkowitzRow Count for each row. */
886  for (I = Step; I <= Size; I++)
887  {
888 /* Set Count to -1 initially to remove count due to pivot element. */
889  Count = -1;
890  pElement = Matrix->FirstInRow[I];
891  while (pElement != NULL AND pElement->Col < Step)
892  pElement = pElement->NextInRow;
893  while (pElement != NULL)
894  { Count++;
895  pElement = pElement->NextInRow;
896  }
897 
898 /* Include nonzero elements in the RHS vector. */
899  ExtRow = Matrix->IntToExtRowMap[I];
900 
901 #if spSEPARATED_COMPLEX_VECTORS OR NOT spCOMPLEX
902  if (RHS != NULL)
903  if (RHS[ExtRow] != 0.0) Count++;
904 #else
905  if (RHS != NULL)
906  { if (Matrix->Complex)
907  { if ((RHS[2*ExtRow] != 0.0) OR (RHS[2*ExtRow+1] != 0.0))
908  Count++;
909  }
910  else if (RHS[I] != 0.0) Count++;
911  }
912 #endif
913  Matrix->MarkowitzRow[I] = Count;
914  }
915 
916 /* Generate the MarkowitzCol count for each column. */
917  for (I = Step; I <= Size; I++)
918  {
919 /* Set Count to -1 initially to remove count due to pivot element. */
920  Count = -1;
921  pElement = Matrix->FirstInCol[I];
922  while (pElement != NULL AND pElement->Row < Step)
923  pElement = pElement->NextInCol;
924  while (pElement != NULL)
925  { Count++;
926  pElement = pElement->NextInCol;
927  }
928  Matrix->MarkowitzCol[I] = Count;
929  }
930  return;
931 }
932 
933 
934 
935 
936 
937 
938 
939 
940 
941 
942 /*
943  * MARKOWITZ PRODUCTS
944  *
945  * Calculates MarkowitzProduct for each diagonal element from the Markowitz
946  * counts.
947  *
948  * >>> Arguments:
949  * Matrix <input> (MatrixPtr)
950  * Pointer to matrix.
951  * Step <input> (int)
952  * Index of the diagonal currently being eliminated.
953  *
954  * >>> Local Variables:
955  * pMarkowitzProduct (long *)
956  * Pointer that points into MarkowitzProduct array. Is used to
957  * sequentially access entries quickly.
958  * pMarkowitzRow (int *)
959  * Pointer that points into MarkowitzRow array. Is used to sequentially
960  * access entries quickly.
961  * pMarkowitzCol (int *)
962  * Pointer that points into MarkowitzCol array. Is used to sequentially
963  * access entries quickly.
964  * Product (long)
965  * Temporary storage for Markowitz product./
966  * Size (int)
967  * The size of the matrix.
968  */
969 
970 static void
971 MarkowitzProducts( Matrix, Step )
972 
973 MatrixPtr Matrix;
974 int Step;
975 {
976 register int I, *pMarkowitzRow, *pMarkowitzCol;
977 register long Product, *pMarkowitzProduct;
978 register int Size = Matrix->Size;
979 double fProduct;
980 
981 /* Begin `MarkowitzProducts'. */
982  Matrix->Singletons = 0;
983 
984  pMarkowitzProduct = &(Matrix->MarkowitzProd[Step]);
985  pMarkowitzRow = &(Matrix->MarkowitzRow[Step]);
986  pMarkowitzCol = &(Matrix->MarkowitzCol[Step]);
987 
988  for (I = Step; I <= Size; I++)
989  {
990 /* If chance of overflow, use real numbers. */
991  if ((*pMarkowitzRow > LARGEST_SHORT_INTEGER AND *pMarkowitzCol != 0) OR
992  (*pMarkowitzCol > LARGEST_SHORT_INTEGER AND *pMarkowitzRow != 0))
993  { fProduct = (double)(*pMarkowitzRow++) * (double)(*pMarkowitzCol++);
994  if (fProduct >= LARGEST_LONG_INTEGER)
995  *pMarkowitzProduct++ = LARGEST_LONG_INTEGER;
996  else
997  *pMarkowitzProduct++ = fProduct;
998  }
999  else
1000  { Product = *pMarkowitzRow++ * *pMarkowitzCol++;
1001  if ((*pMarkowitzProduct++ = Product) == 0)
1002  Matrix->Singletons++;
1003  }
1004  }
1005  return;
1006 }
1007 
1008 
1009 
1010 
1011 
1012 
1013 
1014 
1015 
1016 
1017 
1018 /*
1019  * SEARCH FOR BEST PIVOT
1020  *
1021  * Performs a search to determine the element with the lowest Markowitz
1022  * Product that is also acceptable. An acceptable element is one that is
1023  * larger than the AbsThreshold and at least as large as RelThreshold times
1024  * the largest element in the same column. The first step is to look for
1025  * singletons if any exist. If none are found, then all the diagonals are
1026  * searched. The diagonal is searched once quickly using the assumption that
1027  * elements on the diagonal are large compared to other elements in their
1028  * column, and so the pivot can be chosen only on the basis of the Markowitz
1029  * criterion. After a element has been chosen to be pivot on the basis of
1030  * its Markowitz product, it is checked to see if it is large enough.
1031  * Waiting to the end of the Markowitz search to check the size of a pivot
1032  * candidate saves considerable time, but is not guaranteed to find an
1033  * acceptable pivot. Thus if unsuccessful a second pass of the diagonal is
1034  * made. This second pass checks to see if an element is large enough during
1035  * the search, not after it. If still no acceptable pivot candidate has
1036  * been found, the search expands to cover the entire matrix.
1037  *
1038  * >>> Returned:
1039  * A pointer to the element chosen to be pivot. If every element in the
1040  * matrix is zero, then NULL is returned.
1041  *
1042  * >>> Arguments:
1043  * Matrix <input> (MatrixPtr)
1044  * Pointer to matrix.
1045  * Step <input> (int)
1046  * The row and column number of the beginning of the reduced submatrix.
1047  *
1048  * >>> Local variables:
1049  * ChosenPivot (ElementPtr)
1050  * Pointer to element that has been chosen to be the pivot.
1051  *
1052  * >>> Possible errors:
1053  * spSINGULAR
1054  * spSMALL_PIVOT
1055  */
1056 
1057 static ElementPtr
1058 SearchForPivot( Matrix, Step, DiagPivoting )
1059 
1060 MatrixPtr Matrix;
1061 int Step, DiagPivoting;
1062 {
1063 register ElementPtr ChosenPivot;
1068 
1069 /* Begin `SearchForPivot'. */
1070 
1071 /* If singletons exist, look for an acceptable one to use as pivot. */
1072  if (Matrix->Singletons)
1073  { ChosenPivot = SearchForSingleton( Matrix, Step );
1074  if (ChosenPivot != NULL)
1075  { Matrix->PivotSelectionMethod = 's';
1076  return ChosenPivot;
1077  }
1078  }
1079 
1080 #if DIAGONAL_PIVOTING
1081  if (DiagPivoting)
1082  {
1083 /*
1084  * Either no singletons exist or they weren't acceptable. Take quick first
1085  * pass at searching diagonal. First search for element on diagonal of
1086  * remaining submatrix with smallest Markowitz product, then check to see
1087  * if it okay numerically. If not, QuicklySearchDiagonal fails.
1088  */
1089  ChosenPivot = QuicklySearchDiagonal( Matrix, Step );
1090  if (ChosenPivot != NULL)
1091  { Matrix->PivotSelectionMethod = 'q';
1092  return ChosenPivot;
1093  }
1094 
1095 /*
1096  * Quick search of diagonal failed, carefully search diagonal and check each
1097  * pivot candidate numerically before even tentatively accepting it.
1098  */
1099  ChosenPivot = SearchDiagonal( Matrix, Step );
1100  if (ChosenPivot != NULL)
1101  { Matrix->PivotSelectionMethod = 'd';
1102  return ChosenPivot;
1103  }
1104  }
1105 #endif /* DIAGONAL_PIVOTING */
1106 
1107 /* No acceptable pivot found yet, search entire matrix. */
1108  ChosenPivot = SearchEntireMatrix( Matrix, Step );
1109  Matrix->PivotSelectionMethod = 'e';
1110 
1111  return ChosenPivot;
1112 }
1113 
1114 
1115 
1116 
1117 
1118 
1119 
1120 
1121 
1122 /*
1123  * SEARCH FOR SINGLETON TO USE AS PIVOT
1124  *
1125  * Performs a search to find a singleton to use as the pivot. The
1126  * first acceptable singleton is used. A singleton is acceptable if
1127  * it is larger in magnitude than the AbsThreshold and larger
1128  * than RelThreshold times the largest of any other elements in the same
1129  * column. It may seem that a singleton need not satisfy the
1130  * relative threshold criterion, however it is necessary to prevent
1131  * excessive growth in the RHS from resulting in overflow during the
1132  * forward and backward substitution. A singleton does not need to
1133  * be on the diagonal to be selected.
1134  *
1135  * >>> Returned:
1136  * A pointer to the singleton chosen to be pivot. In no singleton is
1137  * acceptable, return NULL.
1138  *
1139  * >>> Arguments:
1140  * Matrix <input> (MatrixPtr)
1141  * Pointer to matrix.
1142  * Step <input> (int)
1143  * Index of the diagonal currently being eliminated.
1144  *
1145  * >>> Local variables:
1146  * ChosenPivot (ElementPtr)
1147  * Pointer to element that has been chosen to be the pivot.
1148  * PivotMag (RealNumber)
1149  * Magnitude of ChosenPivot.
1150  * Singletons (int)
1151  * The count of the number of singletons that can be used as pivots.
1152  * A local version of Matrix->Singletons.
1153  * pMarkowitzProduct (long *)
1154  * Pointer that points into MarkowitzProduct array. It is used to quickly
1155  * access successive Markowitz products.
1156  */
1157 
1158 static ElementPtr
1159 SearchForSingleton( Matrix, Step )
1160 
1161 MatrixPtr Matrix;
1162 int Step;
1163 {
1164 register ElementPtr ChosenPivot;
1165 register int I;
1166 register long *pMarkowitzProduct;
1167 int Singletons;
1169 
1170 /* Begin `SearchForSingleton'. */
1171 /* Initialize pointer that is to scan through MarkowitzProduct vector. */
1172  pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+1]);
1173  Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step];
1174 
1175 /* Decrement the count of available singletons, on the assumption that an
1176  * acceptable one will be found. */
1177  Singletons = Matrix->Singletons--;
1178 
1179 /*
1180  * Assure that following while loop will always terminate, this is just
1181  * preventive medicine, if things are working right this should never
1182  * be needed.
1183  */
1184  Matrix->MarkowitzProd[Step-1] = 0;
1185 
1186  while (Singletons-- > 0)
1187  {
1188 /* Singletons exist, find them. */
1189 
1190 /*
1191  * This is tricky. Am using a pointer to sequentially step through the
1192  * MarkowitzProduct array. Search terminates when singleton (Product = 0)
1193  * is found. Note that the conditional in the while statement
1194  * ( *pMarkowitzProduct ) is true as long as the MarkowitzProduct is not
1195  * equal to zero. The row (and column) index on the diagonal is then
1196  * calculated by subtracting the pointer to the Markowitz product of
1197  * the first diagonal from the pointer to the Markowitz product of the
1198  * desired element, the singleton.
1199  *
1200  * Search proceeds from the end (high row and column numbers) to the
1201  * beginning (low row and column numbers) so that rows and columns with
1202  * large Markowitz products will tend to be move to the bottom of the
1203  * matrix. However, choosing Diag[Step] is desirable because it would
1204  * require no row and column interchanges, so inspect it first by
1205  * putting its Markowitz product at the end of the MarkowitzProd
1206  * vector.
1207  */
1208 
1209  while ( *pMarkowitzProduct-- )
1210  { /*
1211  * N bottles of beer on the wall;
1212  * N bottles of beer.
1213  * you take one down and pass it around;
1214  * N-1 bottles of beer on the wall.
1215  */
1216  }
1217  I = pMarkowitzProduct - Matrix->MarkowitzProd + 1;
1218 
1219 /* Assure that I is valid. */
1220  if (I < Step) break; /* while (Singletons-- > 0) */
1221  if (I > Matrix->Size) I = Step;
1222 
1223 /* Singleton has been found in either/both row or/and column I. */
1224  if ((ChosenPivot = Matrix->Diag[I]) != NULL)
1225  {
1226 /* Singleton lies on the diagonal. */
1227  PivotMag = ELEMENT_MAG(ChosenPivot);
1228  if
1229  ( PivotMag > Matrix->AbsThreshold AND
1230  PivotMag > Matrix->RelThreshold *
1231  FindBiggestInColExclude( Matrix, ChosenPivot, Step )
1232  ) return ChosenPivot;
1233  }
1234  else
1235  {
1236 /* Singleton does not lie on diagonal, find it. */
1237  if (Matrix->MarkowitzCol[I] == 0)
1238  { ChosenPivot = Matrix->FirstInCol[I];
1239  while ((ChosenPivot != NULL) AND (ChosenPivot->Row < Step))
1240  ChosenPivot = ChosenPivot->NextInCol;
1241  if (ChosenPivot != NULL)
1242  { /* Reduced column has no elements, matrix is singular. */
1243  break;
1244  }
1245  PivotMag = ELEMENT_MAG(ChosenPivot);
1246  if
1247  ( PivotMag > Matrix->AbsThreshold AND
1248  PivotMag > Matrix->RelThreshold *
1249  FindBiggestInColExclude( Matrix, ChosenPivot,
1250  Step )
1251  ) return ChosenPivot;
1252  else
1253  { if (Matrix->MarkowitzRow[I] == 0)
1254  { ChosenPivot = Matrix->FirstInRow[I];
1255  while((ChosenPivot != NULL) AND (ChosenPivot->Col<Step))
1256  ChosenPivot = ChosenPivot->NextInRow;
1257  if (ChosenPivot != NULL)
1258  { /* Reduced row has no elements, matrix is singular. */
1259  break;
1260  }
1261  PivotMag = ELEMENT_MAG(ChosenPivot);
1262  if
1263  ( PivotMag > Matrix->AbsThreshold AND
1264  PivotMag > Matrix->RelThreshold *
1265  FindBiggestInColExclude( Matrix,
1266  ChosenPivot,
1267  Step )
1268  ) return ChosenPivot;
1269  }
1270  }
1271  }
1272  else
1273  { ChosenPivot = Matrix->FirstInRow[I];
1274  while ((ChosenPivot != NULL) AND (ChosenPivot->Col < Step))
1275  ChosenPivot = ChosenPivot->NextInRow;
1276  if (ChosenPivot != NULL)
1277  { /* Reduced row has no elements, matrix is singular. */
1278  break;
1279  }
1280  PivotMag = ELEMENT_MAG(ChosenPivot);
1281  if
1282  ( PivotMag > Matrix->AbsThreshold AND
1283  PivotMag > Matrix->RelThreshold *
1284  FindBiggestInColExclude( Matrix, ChosenPivot,
1285  Step )
1286  ) return ChosenPivot;
1287  }
1288  }
1289 /* Singleton not acceptable (too small), try another. */
1290  } /* end of while(lSingletons>0) */
1291 
1292 /*
1293  * All singletons were unacceptable. Restore Matrix->Singletons count.
1294  * Initial assumption that an acceptable singleton would be found was wrong.
1295  */
1296  Matrix->Singletons++;
1297  return NULL;
1298 }
1299 
1300 
1301 
1302 
1303 
1304 
1305 
1306 
1307 
1308 
1309 
1310 
1311 #if DIAGONAL_PIVOTING
1312 #if MODIFIED_MARKOWITZ
1313 /*
1314  * QUICK SEARCH OF DIAGONAL FOR PIVOT WITH MODIFIED MARKOWITZ CRITERION
1315  *
1316  * Searches the diagonal looking for the best pivot. For a pivot to be
1317  * acceptable it must be larger than the pivot RelThreshold times the largest
1318  * element in its reduced column. Among the acceptable diagonals, the
1319  * one with the smallest MarkowitzProduct is sought. Search terminates
1320  * early if a diagonal is found with a MarkowitzProduct of one and its
1321  * magnitude is larger than the other elements in its row and column.
1322  * Since its MarkowitzProduct is one, there is only one other element in
1323  * both its row and column, and, as a condition for early termination,
1324  * these elements must be located symmetricly in the matrix. If a tie
1325  * occurs between elements of equal MarkowitzProduct, then the element with
1326  * the largest ratio between its magnitude and the largest element in its
1327  * column is used. The search will be terminated after a given number of
1328  * ties have occurred and the best (largest ratio) of the tied element will
1329  * be used as the pivot. The number of ties that will trigger an early
1330  * termination is MinMarkowitzProduct * TIES_MULTIPLIER.
1331  *
1332  * >>> Returned:
1333  * A pointer to the diagonal element chosen to be pivot. If no diagonal is
1334  * acceptable, a NULL is returned.
1335  *
1336  * >>> Arguments:
1337  * Step <input> (int)
1338  * Index of the diagonal currently being eliminated.
1339  *
1340  * >>> Local variables:
1341  * ChosenPivot (ElementPtr)
1342  * Pointer to the element that has been chosen to be the pivot.
1343  * LargestOffDiagonal (RealNumber)
1344  * Magnitude of the largest of the off-diagonal terms associated with
1345  * a diagonal with MarkowitzProduct equal to one.
1346  * Magnitude (RealNumber)
1347  * Absolute value of diagonal element.
1348  * MaxRatio (RealNumber)
1349  * Among the elements tied with the smallest Markowitz product, MaxRatio
1350  * is the best (smallest) ratio of LargestInCol to the diagonal Magnitude
1351  * found so far. The smaller the ratio, the better numerically the
1352  * element will be as pivot.
1353  * MinMarkowitzProduct (long)
1354  * Smallest Markowitz product found of pivot candidates that lie along
1355  * diagonal.
1356  * NumberOfTies (int)
1357  * A count of the number of Markowitz ties that have occurred at current
1358  * MarkowitzProduct.
1359  * pDiag (ElementPtr)
1360  * Pointer to current diagonal element.
1361  * pMarkowitzProduct (long *)
1362  * Pointer that points into MarkowitzProduct array. It is used to quickly
1363  * access successive Markowitz products.
1364  * Ratio (RealNumber)
1365  * For the current pivot candidate, Ratio is the ratio of the largest
1366  * element in its column (excluding itself) to its magnitude.
1367  * TiedElements (ElementPtr[])
1368  * Array of pointers to the elements with the minimum Markowitz
1369  * product.
1370  * pOtherInCol (ElementPtr)
1371  * When there is only one other element in a column other than the
1372  * diagonal, pOtherInCol is used to point to it. Used when Markowitz
1373  * product is to determine if off diagonals are placed symmetricly.
1374  * pOtherInRow (ElementPtr)
1375  * When there is only one other element in a row other than the diagonal,
1376  * pOtherInRow is used to point to it. Used when Markowitz product is
1377  * to determine if off diagonals are placed symmetricly.
1378  */
1379 
1380 static ElementPtr
1381 QuicklySearchDiagonal( Matrix, Step )
1382 
1383 MatrixPtr Matrix;
1384 int Step;
1385 {
1386 register long MinMarkowitzProduct, *pMarkowitzProduct;
1387 register ElementPtr pDiag, pOtherInRow, pOtherInCol;
1388 int I, NumberOfTies;
1389 ElementPtr ChosenPivot, TiedElements[MAX_MARKOWITZ_TIES + 1];
1390 RealNumber Magnitude, LargestInCol, Ratio, MaxRatio;
1391 RealNumber LargestOffDiagonal;
1393 
1394 /* Begin `QuicklySearchDiagonal'. */
1395  NumberOfTies = -1;
1396  MinMarkowitzProduct = LARGEST_LONG_INTEGER;
1397  pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+2]);
1398  Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step];
1399 
1400 /* Assure that following while loop will always terminate. */
1401  Matrix->MarkowitzProd[Step-1] = -1;
1402 
1403 /*
1404  * This is tricky. Am using a pointer in the inner while loop to
1405  * sequentially step through the MarkowitzProduct array. Search
1406  * terminates when the Markowitz product of zero placed at location
1407  * Step-1 is found. The row (and column) index on the diagonal is then
1408  * calculated by subtracting the pointer to the Markowitz product of
1409  * the first diagonal from the pointer to the Markowitz product of the
1410  * desired element. The outer for loop is infinite, broken by using
1411  * break.
1412  *
1413  * Search proceeds from the end (high row and column numbers) to the
1414  * beginning (low row and column numbers) so that rows and columns with
1415  * large Markowitz products will tend to be move to the bottom of the
1416  * matrix. However, choosing Diag[Step] is desirable because it would
1417  * require no row and column interchanges, so inspect it first by
1418  * putting its Markowitz product at the end of the MarkowitzProd
1419  * vector.
1420  */
1421 
1422  for(;;) /* Endless for loop. */
1423  { while (MinMarkowitzProduct < *(--pMarkowitzProduct))
1424  { /*
1425  * N bottles of beer on the wall;
1426  * N bottles of beer.
1427  * You take one down and pass it around;
1428  * N-1 bottles of beer on the wall.
1429  */
1430  }
1431 
1432  I = pMarkowitzProduct - Matrix->MarkowitzProd;
1433 
1434 /* Assure that I is valid; if I < Step, terminate search. */
1435  if (I < Step) break; /* Endless for loop */
1436  if (I > Matrix->Size) I = Step;
1437 
1438  if ((pDiag = Matrix->Diag[I]) == NULL)
1439  continue; /* Endless for loop */
1440  if ((Magnitude = ELEMENT_MAG(pDiag)) <= Matrix->AbsThreshold)
1441  continue; /* Endless for loop */
1442 
1443  if (*pMarkowitzProduct == 1)
1444  {
1445 /* Case where only one element exists in row and column other than diagonal. */
1446 
1447 /* Find off diagonal elements. */
1448  pOtherInRow = pDiag->NextInRow;
1449  pOtherInCol = pDiag->NextInCol;
1450  if (pOtherInRow == NULL AND pOtherInCol == NULL)
1451  { pOtherInRow = Matrix->FirstInRow[I];
1452  while(pOtherInRow != NULL)
1453  { if (pOtherInRow->Col >= Step AND pOtherInRow->Col != I)
1454  break;
1455  pOtherInRow = pOtherInRow->NextInRow;
1456  }
1457  pOtherInCol = Matrix->FirstInCol[I];
1458  while(pOtherInCol != NULL)
1459  { if (pOtherInCol->Row >= Step AND pOtherInCol->Row != I)
1460  break;
1461  pOtherInCol = pOtherInCol->NextInCol;
1462  }
1463  }
1464 
1465 /* Accept diagonal as pivot if diagonal is larger than off diagonals and the
1466  * off diagonals are placed symmetricly. */
1467  if (pOtherInRow != NULL AND pOtherInCol != NULL)
1468  { if (pOtherInRow->Col == pOtherInCol->Row)
1469  { LargestOffDiagonal = MAX(ELEMENT_MAG(pOtherInRow),
1470  ELEMENT_MAG(pOtherInCol));
1471  if (Magnitude >= LargestOffDiagonal)
1472  {
1473 /* Accept pivot, it is unlikely to contribute excess error. */
1474  return pDiag;
1475  }
1476  }
1477  }
1478  }
1479 
1480  if (*pMarkowitzProduct < MinMarkowitzProduct)
1481  {
1482 /* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */
1483  TiedElements[0] = pDiag;
1484  MinMarkowitzProduct = *pMarkowitzProduct;
1485  NumberOfTies = 0;
1486  }
1487  else
1488  {
1489 /* This case handles Markowitz ties. */
1490  if (NumberOfTies < MAX_MARKOWITZ_TIES)
1491  { TiedElements[++NumberOfTies] = pDiag;
1492  if (NumberOfTies >= MinMarkowitzProduct * TIES_MULTIPLIER)
1493  break; /* Endless for loop */
1494  }
1495  }
1496  } /* End of endless for loop. */
1497 
1498 /* Test to see if any element was chosen as a pivot candidate. */
1499  if (NumberOfTies < 0)
1500  return NULL;
1501 
1502 /* Determine which of tied elements is best numerically. */
1503  ChosenPivot = NULL;
1504  MaxRatio = 1.0 / Matrix->RelThreshold;
1505 
1506  for (I = 0; I <= NumberOfTies; I++)
1507  { pDiag = TiedElements[I];
1508  Magnitude = ELEMENT_MAG(pDiag);
1509  LargestInCol = FindBiggestInColExclude( Matrix, pDiag, Step );
1510  Ratio = LargestInCol / Magnitude;
1511  if (Ratio < MaxRatio)
1512  { ChosenPivot = pDiag;
1513  MaxRatio = Ratio;
1514  }
1515  }
1516  return ChosenPivot;
1517 }
1518 
1519 
1520 
1521 
1522 
1523 
1524 
1525 
1526 
1527 
1528 #else /* Not MODIFIED_MARKOWITZ */
1529 /*
1530  * QUICK SEARCH OF DIAGONAL FOR PIVOT WITH CONVENTIONAL MARKOWITZ
1531  * CRITERION
1532  *
1533  * Searches the diagonal looking for the best pivot. For a pivot to be
1534  * acceptable it must be larger than the pivot RelThreshold times the largest
1535  * element in its reduced column. Among the acceptable diagonals, the
1536  * one with the smallest MarkowitzProduct is sought. Search terminates
1537  * early if a diagonal is found with a MarkowitzProduct of one and its
1538  * magnitude is larger than the other elements in its row and column.
1539  * Since its MarkowitzProduct is one, there is only one other element in
1540  * both its row and column, and, as a condition for early termination,
1541  * these elements must be located symmetricly in the matrix.
1542  *
1543  * >>> Returned:
1544  * A pointer to the diagonal element chosen to be pivot. If no diagonal is
1545  * acceptable, a NULL is returned.
1546  *
1547  * >>> Arguments:
1548  * Matrix <input> (MatrixPtr)
1549  * Pointer to matrix.
1550  * Step <input> (int)
1551  * Index of the diagonal currently being eliminated.
1552  *
1553  * >>> Local variables:
1554  * ChosenPivot (ElementPtr)
1555  * Pointer to the element that has been chosen to be the pivot.
1556  * LargestOffDiagonal (RealNumber)
1557  * Magnitude of the largest of the off-diagonal terms associated with
1558  * a diagonal with MarkowitzProduct equal to one.
1559  * Magnitude (RealNumber)
1560  * Absolute value of diagonal element.
1561  * MinMarkowitzProduct (long)
1562  * Smallest Markowitz product found of pivot candidates which are
1563  * acceptable.
1564  * pDiag (ElementPtr)
1565  * Pointer to current diagonal element.
1566  * pMarkowitzProduct (long *)
1567  * Pointer that points into MarkowitzProduct array. It is used to quickly
1568  * access successive Markowitz products.
1569  * pOtherInCol (ElementPtr)
1570  * When there is only one other element in a column other than the
1571  * diagonal, pOtherInCol is used to point to it. Used when Markowitz
1572  * product is to determine if off diagonals are placed symmetricly.
1573  * pOtherInRow (ElementPtr)
1574  * When there is only one other element in a row other than the diagonal,
1575  * pOtherInRow is used to point to it. Used when Markowitz product is
1576  * to determine if off diagonals are placed symmetricly.
1577  */
1578 
1579 static ElementPtr
1580 QuicklySearchDiagonal( Matrix, Step )
1581 
1582 MatrixPtr Matrix;
1583 int Step;
1584 {
1585 register long MinMarkowitzProduct, *pMarkowitzProduct;
1586 register ElementPtr pDiag;
1587 int I;
1588 ElementPtr ChosenPivot, pOtherInRow, pOtherInCol;
1589 RealNumber Magnitude, LargestInCol, LargestOffDiagonal;
1591 
1592 /* Begin `QuicklySearchDiagonal'. */
1593  ChosenPivot = NULL;
1594  MinMarkowitzProduct = LARGEST_LONG_INTEGER;
1595  pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+2]);
1596  Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step];
1597 
1598 /* Assure that following while loop will always terminate. */
1599  Matrix->MarkowitzProd[Step-1] = -1;
1600 
1601 /*
1602  * This is tricky. Am using a pointer in the inner while loop to
1603  * sequentially step through the MarkowitzProduct array. Search
1604  * terminates when the Markowitz product of zero placed at location
1605  * Step-1 is found. The row (and column) index on the diagonal is then
1606  * calculated by subtracting the pointer to the Markowitz product of
1607  * the first diagonal from the pointer to the Markowitz product of the
1608  * desired element. The outer for loop is infinite, broken by using
1609  * break.
1610  *
1611  * Search proceeds from the end (high row and column numbers) to the
1612  * beginning (low row and column numbers) so that rows and columns with
1613  * large Markowitz products will tend to be move to the bottom of the
1614  * matrix. However, choosing Diag[Step] is desirable because it would
1615  * require no row and column interchanges, so inspect it first by
1616  * putting its Markowitz product at the end of the MarkowitzProd
1617  * vector.
1618  */
1619 
1620  for (;;) /* Endless for loop. */
1621  { while (*(--pMarkowitzProduct) >= MinMarkowitzProduct)
1622  { /* Just passing through. */
1623  }
1624 
1625  I = pMarkowitzProduct - Matrix->MarkowitzProd;
1626 
1627 /* Assure that I is valid; if I < Step, terminate search. */
1628  if (I < Step) break; /* Endless for loop */
1629  if (I > Matrix->Size) I = Step;
1630 
1631  if ((pDiag = Matrix->Diag[I]) == NULL)
1632  continue; /* Endless for loop */
1633  if ((Magnitude = ELEMENT_MAG(pDiag)) <= Matrix->AbsThreshold)
1634  continue; /* Endless for loop */
1635 
1636  if (*pMarkowitzProduct == 1)
1637  {
1638 /* Case where only one element exists in row and column other than diagonal. */
1639 
1640 /* Find off-diagonal elements. */
1641  pOtherInRow = pDiag->NextInRow;
1642  pOtherInCol = pDiag->NextInCol;
1643  if (pOtherInRow == NULL AND pOtherInCol == NULL)
1644  { pOtherInRow = Matrix->FirstInRow[I];
1645  while(pOtherInRow != NULL)
1646  { if (pOtherInRow->Col >= Step AND pOtherInRow->Col != I)
1647  break;
1648  pOtherInRow = pOtherInRow->NextInRow;
1649  }
1650  pOtherInCol = Matrix->FirstInCol[I];
1651  while(pOtherInCol != NULL)
1652  { if (pOtherInCol->Row >= Step AND pOtherInCol->Row != I)
1653  break;
1654  pOtherInCol = pOtherInCol->NextInCol;
1655  }
1656  }
1657 
1658 /* Accept diagonal as pivot if diagonal is larger than off-diagonals and the
1659  * off-diagonals are placed symmetricly. */
1660  if (pOtherInRow != NULL AND pOtherInCol != NULL)
1661  { if (pOtherInRow->Col == pOtherInCol->Row)
1662  { LargestOffDiagonal = MAX(ELEMENT_MAG(pOtherInRow),
1663  ELEMENT_MAG(pOtherInCol));
1664  if (Magnitude >= LargestOffDiagonal)
1665  {
1666 /* Accept pivot, it is unlikely to contribute excess error. */
1667  return pDiag;
1668  }
1669  }
1670  }
1671  }
1672 
1673  MinMarkowitzProduct = *pMarkowitzProduct;
1674  ChosenPivot = pDiag;
1675  } /* End of endless for loop. */
1676 
1677  if (ChosenPivot != NULL)
1678  { LargestInCol = FindBiggestInColExclude( Matrix, ChosenPivot, Step );
1679  if( ELEMENT_MAG(ChosenPivot) <= Matrix->RelThreshold * LargestInCol )
1680  ChosenPivot = NULL;
1681  }
1682  return ChosenPivot;
1683 }
1684 #endif /* Not MODIFIED_MARKOWITZ */
1685 
1686 
1687 
1688 
1689 
1690 
1691 
1692 
1693 
1694 /*
1695  * SEARCH DIAGONAL FOR PIVOT WITH MODIFIED MARKOWITZ CRITERION
1696  *
1697  * Searches the diagonal looking for the best pivot. For a pivot to be
1698  * acceptable it must be larger than the pivot RelThreshold times the largest
1699  * element in its reduced column. Among the acceptable diagonals, the
1700  * one with the smallest MarkowitzProduct is sought. If a tie occurs
1701  * between elements of equal MarkowitzProduct, then the element with
1702  * the largest ratio between its magnitude and the largest element in its
1703  * column is used. The search will be terminated after a given number of
1704  * ties have occurred and the best (smallest ratio) of the tied element will
1705  * be used as the pivot. The number of ties that will trigger an early
1706  * termination is MinMarkowitzProduct * TIES_MULTIPLIER.
1707  *
1708  * >>> Returned:
1709  * A pointer to the diagonal element chosen to be pivot. If no diagonal is
1710  * acceptable, a NULL is returned.
1711  *
1712  * >>> Arguments:
1713  * Matrix <input> (MatrixPtr)
1714  * Pointer to matrix.
1715  * Step <input> (int)
1716  * Index of the diagonal currently being eliminated.
1717  *
1718  * >>> Local variables:
1719  * ChosenPivot (ElementPtr)
1720  * Pointer to the element that has been chosen to be the pivot.
1721  * Size (int)
1722  * Local version of size which is placed in a register to increase speed.
1723  * Magnitude (RealNumber)
1724  * Absolute value of diagonal element.
1725  * MinMarkowitzProduct (long)
1726  * Smallest Markowitz product found of those pivot candidates which are
1727  * acceptable.
1728  * NumberOfTies (int)
1729  * A count of the number of Markowitz ties that have occurred at current
1730  * MarkowitzProduct.
1731  * pDiag (ElementPtr)
1732  * Pointer to current diagonal element.
1733  * pMarkowitzProduct (long*)
1734  * Pointer that points into MarkowitzProduct array. It is used to quickly
1735  * access successive Markowitz products.
1736  * Ratio (RealNumber)
1737  * For the current pivot candidate, Ratio is the
1738  * Ratio of the largest element in its column to its magnitude.
1739  * RatioOfAccepted (RealNumber)
1740  * For the best pivot candidate found so far, RatioOfAccepted is the
1741  * Ratio of the largest element in its column to its magnitude.
1742  */
1743 
1744 static ElementPtr
1745 SearchDiagonal( Matrix, Step )
1746 
1747 MatrixPtr Matrix;
1748 register int Step;
1749 {
1750 register int J;
1751 register long MinMarkowitzProduct, *pMarkowitzProduct;
1752 register int I;
1753 register ElementPtr pDiag;
1754 int NumberOfTies, Size = Matrix->Size;
1755 ElementPtr ChosenPivot;
1756 RealNumber Magnitude, Ratio, RatioOfAccepted, LargestInCol;
1758 
1759 /* Begin `SearchDiagonal'. */
1760  ChosenPivot = NULL;
1761  MinMarkowitzProduct = LARGEST_LONG_INTEGER;
1762  pMarkowitzProduct = &(Matrix->MarkowitzProd[Size+2]);
1763  Matrix->MarkowitzProd[Size+1] = Matrix->MarkowitzProd[Step];
1764 
1765 /* Start search of diagonal. */
1766  for (J = Size+1; J > Step; J--)
1767  {
1768  if (*(--pMarkowitzProduct) > MinMarkowitzProduct)
1769  continue; /* for loop */
1770  if (J > Matrix->Size)
1771  I = Step;
1772  else
1773  I = J;
1774  if ((pDiag = Matrix->Diag[I]) == NULL)
1775  continue; /* for loop */
1776  if ((Magnitude = ELEMENT_MAG(pDiag)) <= Matrix->AbsThreshold)
1777  continue; /* for loop */
1778 
1779 /* Test to see if diagonal's magnitude is acceptable. */
1780  LargestInCol = FindBiggestInColExclude( Matrix, pDiag, Step );
1781  if (Magnitude <= Matrix->RelThreshold * LargestInCol)
1782  continue; /* for loop */
1783 
1784  if (*pMarkowitzProduct < MinMarkowitzProduct)
1785  {
1786 /* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */
1787  ChosenPivot = pDiag;
1788  MinMarkowitzProduct = *pMarkowitzProduct;
1789  RatioOfAccepted = LargestInCol / Magnitude;
1790  NumberOfTies = 0;
1791  }
1792  else
1793  {
1794 /* This case handles Markowitz ties. */
1795  NumberOfTies++;
1796  Ratio = LargestInCol / Magnitude;
1797  if (Ratio < RatioOfAccepted)
1798  { ChosenPivot = pDiag;
1799  RatioOfAccepted = Ratio;
1800  }
1801  if (NumberOfTies >= MinMarkowitzProduct * TIES_MULTIPLIER)
1802  return ChosenPivot;
1803  }
1804  } /* End of for(Step) */
1805  return ChosenPivot;
1806 }
1807 #endif /* DIAGONAL_PIVOTING */
1808 
1809 
1810 
1811 
1812 
1813 
1814 
1815 
1816 
1817 
1818 /*
1819  * SEARCH ENTIRE MATRIX FOR BEST PIVOT
1820  *
1821  * Performs a search over the entire matrix looking for the acceptable
1822  * element with the lowest MarkowitzProduct. If there are several that
1823  * are tied for the smallest MarkowitzProduct, the tie is broken by using
1824  * the ratio of the magnitude of the element being considered to the largest
1825  * element in the same column. If no element is acceptable then the largest
1826  * element in the reduced submatrix is used as the pivot and the
1827  * matrix is declared to be spSMALL_PIVOT. If the largest element is
1828  * zero, the matrix is declared to be spSINGULAR.
1829  *
1830  * >>> Returned:
1831  * A pointer to the diagonal element chosen to be pivot. If no element is
1832  * found, then NULL is returned and the matrix is spSINGULAR.
1833  *
1834  * >>> Arguments:
1835  * Matrix <input> (MatrixPtr)
1836  * Pointer to matrix.
1837  * Step <input> (int)
1838  * Index of the diagonal currently being eliminated.
1839  *
1840  * >>> Local variables:
1841  * ChosenPivot (ElementPtr)
1842  * Pointer to the element that has been chosen to be the pivot.
1843  * LargestElementMag (RealNumber)
1844  * Magnitude of the largest element yet found in the reduced submatrix.
1845  * Size (int)
1846  * Local version of Size; placed in a register for speed.
1847  * Magnitude (RealNumber)
1848  * Absolute value of diagonal element.
1849  * MinMarkowitzProduct (long)
1850  * Smallest Markowitz product found of pivot candidates which are
1851  * acceptable.
1852  * NumberOfTies (int)
1853  * A count of the number of Markowitz ties that have occurred at current
1854  * MarkowitzProduct.
1855  * pElement (ElementPtr)
1856  * Pointer to current element.
1857  * pLargestElement (ElementPtr)
1858  * Pointer to the largest element yet found in the reduced submatrix.
1859  * Product (long)
1860  * Markowitz product for the current row and column.
1861  * Ratio (RealNumber)
1862  * For the current pivot candidate, Ratio is the
1863  * Ratio of the largest element in its column to its magnitude.
1864  * RatioOfAccepted (RealNumber)
1865  * For the best pivot candidate found so far, RatioOfAccepted is the
1866  * Ratio of the largest element in its column to its magnitude.
1867  *
1868  * >>> Possible errors:
1869  * spSINGULAR
1870  * spSMALL_PIVOT
1871  */
1872 
1873 static ElementPtr
1874 SearchEntireMatrix( Matrix, Step )
1875 
1876 MatrixPtr Matrix;
1877 int Step;
1878 {
1879 register int I, Size = Matrix->Size;
1880 register ElementPtr pElement;
1881 int NumberOfTies;
1882 long Product, MinMarkowitzProduct;
1883 ElementPtr ChosenPivot, pLargestElement;
1884 RealNumber Magnitude, LargestElementMag, Ratio, RatioOfAccepted, LargestInCol;
1886 
1887 /* Begin `SearchEntireMatrix'. */
1888  ChosenPivot = NULL;
1889  LargestElementMag = 0.0;
1890  MinMarkowitzProduct = LARGEST_LONG_INTEGER;
1891 
1892 /* Start search of matrix on column by column basis. */
1893  for (I = Step; I <= Size; I++)
1894  { pElement = Matrix->FirstInCol[I];
1895 
1896  while (pElement != NULL AND pElement->Row < Step)
1897  pElement = pElement->NextInCol;
1898 
1899  if((LargestInCol = FindLargestInCol(Matrix,pElement)) == 0.0)
1900  continue; /* for loop */
1901 
1902  while (pElement != NULL)
1903  {
1904 /* Check to see if element is the largest encountered so far. If so, record
1905  its magnitude and address. */
1906  if ((Magnitude = ELEMENT_MAG(pElement)) > LargestElementMag)
1907  { LargestElementMag = Magnitude;
1908  pLargestElement = pElement;
1909  }
1910 /* Calculate element's MarkowitzProduct. */
1911  Product = Matrix->MarkowitzRow[pElement->Row] *
1912  Matrix->MarkowitzCol[pElement->Col];
1913 
1914 /* Test to see if element is acceptable as a pivot candidate. */
1915  if ((Product <= MinMarkowitzProduct) AND
1916  (Magnitude > Matrix->RelThreshold * LargestInCol) AND
1917  (Magnitude > Matrix->AbsThreshold))
1918  {
1919 /* Test to see if element has lowest MarkowitzProduct yet found, or whether it
1920  is tied with an element found earlier. */
1921  if (Product < MinMarkowitzProduct)
1922  {
1923 /* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */
1924  ChosenPivot = pElement;
1925  MinMarkowitzProduct = Product;
1926  RatioOfAccepted = LargestInCol / Magnitude;
1927  NumberOfTies = 0;
1928  }
1929  else
1930  {
1931 /* This case handles Markowitz ties. */
1932  NumberOfTies++;
1933  Ratio = LargestInCol / Magnitude;
1934  if (Ratio < RatioOfAccepted)
1935  { ChosenPivot = pElement;
1936  RatioOfAccepted = Ratio;
1937  }
1938  if (NumberOfTies >= MinMarkowitzProduct * TIES_MULTIPLIER)
1939  return ChosenPivot;
1940  }
1941  }
1942  pElement = pElement->NextInCol;
1943  } /* End of while(pElement != NULL) */
1944  } /* End of for(Step) */
1945 
1946  if (ChosenPivot != NULL) return ChosenPivot;
1947 
1948  if (LargestElementMag == 0.0)
1949  { Matrix->Error = spSINGULAR;
1950  return NULL;
1951  }
1952 
1953  Matrix->Error = spSMALL_PIVOT;
1954  return pLargestElement;
1955 }
1956 
1957 
1958 
1959 
1960 
1961 
1962 
1963 
1964 
1965 
1966 
1967 
1968 /*
1969  * DETERMINE THE MAGNITUDE OF THE LARGEST ELEMENT IN A COLUMN
1970  *
1971  * This routine searches a column and returns the magnitude of the largest
1972  * element. This routine begins the search at the element pointed to by
1973  * pElement, the parameter.
1974  *
1975  * The search is conducted by starting at the element specified by a pointer,
1976  * which should be one below the diagonal, and moving down the column. On
1977  * the way down the column, the magnitudes of the elements are tested to see
1978  * if they are the largest yet found.
1979  *
1980  * >>> Returned:
1981  * The magnitude of the largest element in the column below and including
1982  * the one pointed to by the input parameter.
1983  *
1984  * >>> Arguments:
1985  * pElement <input> (ElementPtr)
1986  * The pointer to the first element to be tested. Also, used by the
1987  * routine to access all lower elements in the column.
1988  *
1989  * >>> Local variables:
1990  * Largest (RealNumber)
1991  * The magnitude of the largest element.
1992  * Magnitude (RealNumber)
1993  * The magnitude of the currently active element.
1994  */
1995 
1996 static RealNumber
1998 
1999 MatrixPtr Matrix; /* SRW added - used in ELEMENT_MAG() */
2000 register ElementPtr pElement;
2001 {
2002 RealNumber Magnitude, Largest = 0.0;
2003 
2004 /* Begin `FindLargestInCol'. */
2005 /* Search column for largest element beginning at Element. */
2006  while (pElement != NULL)
2007  { if ((Magnitude = ELEMENT_MAG(pElement)) > Largest)
2008  Largest = Magnitude;
2009  pElement = pElement->NextInCol;
2010  }
2011 
2012  return Largest;
2013 }
2014 
2015 
2016 
2017 
2018 
2019 
2020 
2021 
2022 
2023 
2024 /*
2025  * DETERMINE THE MAGNITUDE OF THE LARGEST ELEMENT IN A COLUMN
2026  * EXCLUDING AN ELEMENT
2027  *
2028  * This routine searches a column and returns the magnitude of the largest
2029  * element. One given element is specifically excluded from the search.
2030  *
2031  * The search is conducted by starting at the first element in the column
2032  * and moving down the column until the active part of the matrix is entered,
2033  * i.e. the reduced submatrix. The rest of the column is then traversed
2034  * looking for the largest element.
2035  *
2036  * >>> Returned:
2037  * The magnitude of the largest element in the active portion of the column,
2038  * excluding the specified element, is returned.
2039  *
2040  * >>> Arguments:
2041  * Matrix <input> (MatrixPtr)
2042  * Pointer to the matrix.
2043  * pElement <input> (ElementPtr)
2044  * The pointer to the element that is to be excluded from search. Column
2045  * to be searched is one that contains this element. Also used to
2046  * access the elements in the column.
2047  * Step <input> (int)
2048  * Index of the diagonal currently being eliminated. Indicates where
2049  * the active part of the matrix begins.
2050  *
2051  * >>> Local variables:
2052  * Col (int)
2053  * The number of the column to be searched. Also the column number of
2054  * the element to be avoided in the search.
2055  * Largest (RealNumber)
2056  * The magnitude of the largest element.
2057  * Magnitude (RealNumber)
2058  * The magnitude of the currently active element.
2059  * Row (int)
2060  * The row number of element to be excluded from the search.
2061  */
2062 
2063 static RealNumber
2065 
2066 MatrixPtr Matrix;
2067 register ElementPtr pElement;
2068 register int Step;
2069 {
2070 register int Row;
2071 int Col;
2072 RealNumber Largest, Magnitude;
2073 
2074 /* Begin `FindBiggestInColExclude'. */
2075  Row = pElement->Row;
2076  Col = pElement->Col;
2077  pElement = Matrix->FirstInCol[Col];
2078 
2079 /* Travel down column until reduced submatrix is entered. */
2080  while ((pElement != NULL) AND (pElement->Row < Step))
2081  pElement = pElement->NextInCol;
2082 
2083 /* Initialize the variable Largest. */
2084  if (pElement->Row != Row)
2085  Largest = ELEMENT_MAG(pElement);
2086  else
2087  Largest = 0.0;
2088 
2089 /* Search rest of column for largest element, avoiding excluded element. */
2090  while ((pElement = pElement->NextInCol) != NULL)
2091  { if ((Magnitude = ELEMENT_MAG(pElement)) > Largest)
2092  { if (pElement->Row != Row)
2093  Largest = Magnitude;
2094  }
2095  }
2096 
2097  return Largest;
2098 }
2099 
2100 
2101 
2102 
2103 
2104 
2105 
2106 
2107 
2108 
2109 /*
2110  * EXCHANGE ROWS AND COLUMNS
2111  *
2112  * Exchanges two rows and two columns so that the selected pivot is moved to
2113  * the upper left corner of the remaining submatrix.
2114  *
2115  * >>> Arguments:
2116  * Matrix <input> (MatrixPtr)
2117  * Pointer to the matrix.
2118  * pPivot <input> (ElementPtr)
2119  * Pointer to the current pivot.
2120  * Step <input> (int)
2121  * Index of the diagonal currently being eliminated.
2122  *
2123  * >>> Local variables:
2124  * Col (int)
2125  * Column where the pivot was found.
2126  * Row (int)
2127  * Row where the pivot was found.
2128  * OldMarkowitzProd_Col (long)
2129  * Markowitz product associated with the diagonal element in the row
2130  * the pivot was found in.
2131  * OldMarkowitzProd_Row (long)
2132  * Markowitz product associated with the diagonal element in the column
2133  * the pivot was found in.
2134  * OldMarkowitzProd_Step (long)
2135  * Markowitz product associated with the diagonal element that is being
2136  * moved so that the pivot can be placed in the upper left-hand corner
2137  * of the reduced submatrix.
2138  */
2139 
2140 static void
2141 ExchangeRowsAndCols( Matrix, pPivot, Step )
2142 
2143 MatrixPtr Matrix;
2145 register int Step;
2146 {
2147 register int Row, Col;
2148 long OldMarkowitzProd_Step, OldMarkowitzProd_Row, OldMarkowitzProd_Col;
2150 
2151 /* Begin `ExchangeRowsAndCols'. */
2152  Row = pPivot->Row;
2153  Col = pPivot->Col;
2154  Matrix->PivotsOriginalRow = Row;
2155  Matrix->PivotsOriginalCol = Col;
2156 
2157  if ((Row == Step) AND (Col == Step)) return;
2158 
2159 /* Exchange rows and columns. */
2160  if (Row == Col)
2161  { spcRowExchange( Matrix, Step, Row );
2162  spcColExchange( Matrix, Step, Col );
2163  SWAP( long, Matrix->MarkowitzProd[Step], Matrix->MarkowitzProd[Row] );
2164  SWAP( ElementPtr, Matrix->Diag[Row], Matrix->Diag[Step] );
2165  }
2166  else
2167  {
2168 
2169 /* Initialize variables that hold old Markowitz products. */
2170  OldMarkowitzProd_Step = Matrix->MarkowitzProd[Step];
2171  OldMarkowitzProd_Row = Matrix->MarkowitzProd[Row];
2172  OldMarkowitzProd_Col = Matrix->MarkowitzProd[Col];
2173 
2174 /* Exchange rows. */
2175  if (Row != Step)
2176  { spcRowExchange( Matrix, Step, Row );
2177  Matrix->NumberOfInterchangesIsOdd =
2178  NOT Matrix->NumberOfInterchangesIsOdd;
2179  Matrix->MarkowitzProd[Row] = Matrix->MarkowitzRow[Row] *
2180  Matrix->MarkowitzCol[Row];
2181 
2182 /* Update singleton count. */
2183  if ((Matrix->MarkowitzProd[Row]==0) != (OldMarkowitzProd_Row==0))
2184  { if (OldMarkowitzProd_Row == 0)
2185  Matrix->Singletons--;
2186  else
2187  Matrix->Singletons++;
2188  }
2189  }
2190 
2191 /* Exchange columns. */
2192  if (Col != Step)
2193  { spcColExchange( Matrix, Step, Col );
2194  Matrix->NumberOfInterchangesIsOdd =
2195  NOT Matrix->NumberOfInterchangesIsOdd;
2196  Matrix->MarkowitzProd[Col] = Matrix->MarkowitzCol[Col] *
2197  Matrix->MarkowitzRow[Col];
2198 
2199 /* Update singleton count. */
2200  if ((Matrix->MarkowitzProd[Col]==0) != (OldMarkowitzProd_Col==0))
2201  { if (OldMarkowitzProd_Col == 0)
2202  Matrix->Singletons--;
2203  else
2204  Matrix->Singletons++;
2205  }
2206 
2207  Matrix->Diag[Col] = spcFindElementInCol( Matrix,
2208  Matrix->FirstInCol+Col,
2209  Col, Col, NO );
2210  }
2211  if (Row != Step)
2212  { Matrix->Diag[Row] = spcFindElementInCol( Matrix,
2213  Matrix->FirstInCol+Row,
2214  Row, Row, NO );
2215  }
2216  Matrix->Diag[Step] = spcFindElementInCol( Matrix,
2217  Matrix->FirstInCol+Step,
2218  Step, Step, NO );
2219 
2220 /* Update singleton count. */
2221  Matrix->MarkowitzProd[Step] = Matrix->MarkowitzCol[Step] *
2222  Matrix->MarkowitzRow[Step];
2223  if ((Matrix->MarkowitzProd[Step]==0) != (OldMarkowitzProd_Step==0))
2224  { if (OldMarkowitzProd_Step == 0)
2225  Matrix->Singletons--;
2226  else
2227  Matrix->Singletons++;
2228  }
2229  }
2230  return;
2231 }
2232 
2233 
2234 
2235 
2236 
2237 
2238 
2239 
2240 
2241 /*
2242  * EXCHANGE ROWS
2243  *
2244  * Performs all required operations to exchange two rows. Those operations
2245  * include: swap FirstInRow pointers, fixing up the NextInCol pointers,
2246  * swapping row indexes in MatrixElements, and swapping Markowitz row
2247  * counts.
2248  *
2249  * >>> Arguments:
2250  * Matrix <input> (MatrixPtr)
2251  * Pointer to the matrix.
2252  * Row1 <input> (int)
2253  * Row index of one of the rows, becomes the smallest index.
2254  * Row2 <input> (int)
2255  * Row index of the other row, becomes the largest index.
2256  *
2257  * Local variables:
2258  * Column (int)
2259  * Column in which row elements are currently being exchanged.
2260  * Row1Ptr (ElementPtr)
2261  * Pointer to an element in Row1.
2262  * Row2Ptr (ElementPtr)
2263  * Pointer to an element in Row2.
2264  * Element1 (ElementPtr)
2265  * Pointer to the element in Row1 to be exchanged.
2266  * Element2 (ElementPtr)
2267  * Pointer to the element in Row2 to be exchanged.
2268  */
2269 
2270 void
2271 spcRowExchange( Matrix, Row1, Row2 )
2272 
2273 MatrixPtr Matrix;
2274 int Row1, Row2;
2275 {
2276 register ElementPtr Row1Ptr, Row2Ptr;
2277 int Column;
2279 
2280 /* Begin `spcRowExchange'. */
2281  if (Row1 > Row2) SWAP(int, Row1, Row2);
2282 
2283  Row1Ptr = Matrix->FirstInRow[Row1];
2284  Row2Ptr = Matrix->FirstInRow[Row2];
2285  while (Row1Ptr != NULL OR Row2Ptr != NULL)
2286  {
2287 /* Exchange elements in rows while traveling from left to right. */
2288  if (Row1Ptr == NULL)
2289  { Column = Row2Ptr->Col;
2290  Element1 = NULL;
2291  Element2 = Row2Ptr;
2292  Row2Ptr = Row2Ptr->NextInRow;
2293  }
2294  else if (Row2Ptr == NULL)
2295  { Column = Row1Ptr->Col;
2296  Element1 = Row1Ptr;
2297  Element2 = NULL;
2298  Row1Ptr = Row1Ptr->NextInRow;
2299  }
2300  else if (Row1Ptr->Col < Row2Ptr->Col)
2301  { Column = Row1Ptr->Col;
2302  Element1 = Row1Ptr;
2303  Element2 = NULL;
2304  Row1Ptr = Row1Ptr->NextInRow;
2305  }
2306  else if (Row1Ptr->Col > Row2Ptr->Col)
2307  { Column = Row2Ptr->Col;
2308  Element1 = NULL;
2309  Element2 = Row2Ptr;
2310  Row2Ptr = Row2Ptr->NextInRow;
2311  }
2312  else /* Row1Ptr->Col == Row2Ptr->Col */
2313  { Column = Row1Ptr->Col;
2314  Element1 = Row1Ptr;
2315  Element2 = Row2Ptr;
2316  Row1Ptr = Row1Ptr->NextInRow;
2317  Row2Ptr = Row2Ptr->NextInRow;
2318  }
2319 
2320  ExchangeColElements( Matrix, Row1, Element1, Row2, Element2, Column);
2321  } /* end of while(Row1Ptr != NULL OR Row2Ptr != NULL) */
2322 
2323  if (Matrix->InternalVectorsAllocated)
2324  SWAP( int, Matrix->MarkowitzRow[Row1], Matrix->MarkowitzRow[Row2]);
2325  SWAP( ElementPtr, Matrix->FirstInRow[Row1], Matrix->FirstInRow[Row2]);
2326  SWAP( int, Matrix->IntToExtRowMap[Row1], Matrix->IntToExtRowMap[Row2]);
2327 #if TRANSLATE
2328  Matrix->ExtToIntRowMap[ Matrix->IntToExtRowMap[Row1] ] = Row1;
2329  Matrix->ExtToIntRowMap[ Matrix->IntToExtRowMap[Row2] ] = Row2;
2330 #endif
2331 
2332  return;
2333 }
2334 
2335 
2336 
2337 
2338 
2339 
2340 
2341 
2342 
2343 /*
2344  * EXCHANGE COLUMNS
2345  *
2346  * Performs all required operations to exchange two columns. Those operations
2347  * include: swap FirstInCol pointers, fixing up the NextInRow pointers,
2348  * swapping column indexes in MatrixElements, and swapping Markowitz
2349  * column counts.
2350  *
2351  * >>> Arguments:
2352  * Matrix <input> (MatrixPtr)
2353  * Pointer to the matrix.
2354  * Col1 <input> (int)
2355  * Column index of one of the columns, becomes the smallest index.
2356  * Col2 <input> (int)
2357  * Column index of the other column, becomes the largest index
2358  *
2359  * Local variables:
2360  * Row (int)
2361  * Row in which column elements are currently being exchanged.
2362  * Col1Ptr (ElementPtr)
2363  * Pointer to an element in Col1.
2364  * Col2Ptr (ElementPtr)
2365  * Pointer to an element in Col2.
2366  * Element1 (ElementPtr)
2367  * Pointer to the element in Col1 to be exchanged.
2368  * Element2 (ElementPtr)
2369  * Pointer to the element in Col2 to be exchanged.
2370  */
2371 
2372 void
2373 spcColExchange( Matrix, Col1, Col2 )
2374 
2375 MatrixPtr Matrix;
2376 int Col1, Col2;
2377 {
2378 register ElementPtr Col1Ptr, Col2Ptr;
2379 int Row;
2381 
2382 /* Begin `spcColExchange'. */
2383  if (Col1 > Col2) SWAP(int, Col1, Col2);
2384 
2385  Col1Ptr = Matrix->FirstInCol[Col1];
2386  Col2Ptr = Matrix->FirstInCol[Col2];
2387  while (Col1Ptr != NULL OR Col2Ptr != NULL)
2388  {
2389 /* Exchange elements in rows while traveling from top to bottom. */
2390  if (Col1Ptr == NULL)
2391  { Row = Col2Ptr->Row;
2392  Element1 = NULL;
2393  Element2 = Col2Ptr;
2394  Col2Ptr = Col2Ptr->NextInCol;
2395  }
2396  else if (Col2Ptr == NULL)
2397  { Row = Col1Ptr->Row;
2398  Element1 = Col1Ptr;
2399  Element2 = NULL;
2400  Col1Ptr = Col1Ptr->NextInCol;
2401  }
2402  else if (Col1Ptr->Row < Col2Ptr->Row)
2403  { Row = Col1Ptr->Row;
2404  Element1 = Col1Ptr;
2405  Element2 = NULL;
2406  Col1Ptr = Col1Ptr->NextInCol;
2407  }
2408  else if (Col1Ptr->Row > Col2Ptr->Row)
2409  { Row = Col2Ptr->Row;
2410  Element1 = NULL;
2411  Element2 = Col2Ptr;
2412  Col2Ptr = Col2Ptr->NextInCol;
2413  }
2414  else /* Col1Ptr->Row == Col2Ptr->Row */
2415  { Row = Col1Ptr->Row;
2416  Element1 = Col1Ptr;
2417  Element2 = Col2Ptr;
2418  Col1Ptr = Col1Ptr->NextInCol;
2419  Col2Ptr = Col2Ptr->NextInCol;
2420  }
2421 
2422  ExchangeRowElements( Matrix, Col1, Element1, Col2, Element2, Row);
2423  } /* end of while(Col1Ptr != NULL OR Col2Ptr != NULL) */
2424 
2425  if (Matrix->InternalVectorsAllocated)
2426  SWAP( int, Matrix->MarkowitzCol[Col1], Matrix->MarkowitzCol[Col2]);
2427  SWAP( ElementPtr, Matrix->FirstInCol[Col1], Matrix->FirstInCol[Col2]);
2428  SWAP( int, Matrix->IntToExtColMap[Col1], Matrix->IntToExtColMap[Col2]);
2429 #if TRANSLATE
2430  Matrix->ExtToIntColMap[ Matrix->IntToExtColMap[Col1] ] = Col1;
2431  Matrix->ExtToIntColMap[ Matrix->IntToExtColMap[Col2] ] = Col2;
2432 #endif
2433 
2434  return;
2435 }
2436 
2437 
2438 
2439 
2440 
2441 
2442 
2443 /*
2444  * EXCHANGE TWO ELEMENTS IN A COLUMN
2445  *
2446  * Performs all required operations to exchange two elements in a column.
2447  * Those operations are: restring NextInCol pointers and swapping row indexes
2448  * in the MatrixElements.
2449  *
2450  * >>> Arguments:
2451  * Matrix <input> (MatrixPtr)
2452  * Pointer to the matrix.
2453  * Row1 <input> (int)
2454  * Row of top element to be exchanged.
2455  * Element1 <input> (ElementPtr)
2456  * Pointer to top element to be exchanged.
2457  * Row2 <input> (int)
2458  * Row of bottom element to be exchanged.
2459  * Element2 <input> (ElementPtr)
2460  * Pointer to bottom element to be exchanged.
2461  * Column <input> (int)
2462  * Column that exchange is to take place in.
2463  *
2464  * >>> Local variables:
2465  * ElementAboveRow1 (ElementPtr *)
2466  * Location of pointer which points to the element above Element1. This
2467  * pointer is modified so that it points to correct element on exit.
2468  * ElementAboveRow2 (ElementPtr *)
2469  * Location of pointer which points to the element above Element2. This
2470  * pointer is modified so that it points to correct element on exit.
2471  * ElementBelowRow1 (ElementPtr)
2472  * Pointer to element below Element1.
2473  * ElementBelowRow2 (ElementPtr)
2474  * Pointer to element below Element2.
2475  * pElement (ElementPtr)
2476  * Pointer used to traverse the column.
2477  */
2478 
2479 static void
2480 ExchangeColElements( Matrix, Row1, Element1, Row2, Element2, Column )
2481 
2482 MatrixPtr Matrix;
2483 register ElementPtr Element1, Element2;
2484 int Row1, Row2, Column;
2485 {
2486 ElementPtr *ElementAboveRow1, *ElementAboveRow2;
2487 ElementPtr ElementBelowRow1, ElementBelowRow2;
2488 register ElementPtr pElement;
2489 
2490 /* Begin `ExchangeColElements'. */
2491 /* Search to find the ElementAboveRow1. */
2492  ElementAboveRow1 = &(Matrix->FirstInCol[Column]);
2493  pElement = *ElementAboveRow1;
2494  while (pElement->Row < Row1)
2495  { ElementAboveRow1 = &(pElement->NextInCol);
2496  pElement = *ElementAboveRow1;
2497  }
2498  if (Element1 != NULL)
2499  { ElementBelowRow1 = Element1->NextInCol;
2500  if (Element2 == NULL)
2501  {
2502 /* Element2 does not exist, move Element1 down to Row2. */
2503  if ( ElementBelowRow1 != NULL AND ElementBelowRow1->Row < Row2 )
2504  {
2505 /* Element1 must be removed from linked list and moved. */
2506  *ElementAboveRow1 = ElementBelowRow1;
2507 
2508 /* Search column for Row2. */
2509  pElement = ElementBelowRow1;
2510  do
2511  { ElementAboveRow2 = &(pElement->NextInCol);
2512  pElement = *ElementAboveRow2;
2513  } while (pElement != NULL AND pElement->Row < Row2);
2514 
2515 /* Place Element1 in Row2. */
2516  *ElementAboveRow2 = Element1;
2517  Element1->NextInCol = pElement;
2518  *ElementAboveRow1 =ElementBelowRow1;
2519  }
2520  Element1->Row = Row2;
2521  }
2522  else
2523  {
2524 /* Element2 does exist, and the two elements must be exchanged. */
2525  if ( ElementBelowRow1->Row == Row2)
2526  {
2527 /* Element2 is just below Element1, exchange them. */
2528  Element1->NextInCol = Element2->NextInCol;
2529  Element2->NextInCol = Element1;
2530  *ElementAboveRow1 = Element2;
2531  }
2532  else
2533  {
2534 /* Element2 is not just below Element1 and must be searched for. */
2535  pElement = ElementBelowRow1;
2536  do
2537  { ElementAboveRow2 = &(pElement->NextInCol);
2538  pElement = *ElementAboveRow2;
2539  } while (pElement->Row < Row2);
2540 
2541  ElementBelowRow2 = Element2->NextInCol;
2542 
2543 /* Switch Element1 and Element2. */
2544  *ElementAboveRow1 = Element2;
2545  Element2->NextInCol = ElementBelowRow1;
2546  *ElementAboveRow2 = Element1;
2547  Element1->NextInCol = ElementBelowRow2;
2548  }
2549  Element1->Row = Row2;
2550  Element2->Row = Row1;
2551  }
2552  }
2553  else
2554  {
2555 /* Element1 does not exist. */
2556  ElementBelowRow1 = pElement;
2557 
2558 /* Find Element2. */
2559  if (ElementBelowRow1->Row != Row2)
2560  { do
2561  { ElementAboveRow2 = &(pElement->NextInCol);
2562  pElement = *ElementAboveRow2;
2563  } while (pElement->Row < Row2);
2564 
2565  ElementBelowRow2 = Element2->NextInCol;
2566 
2567 /* Move Element2 to Row1. */
2568  *ElementAboveRow2 = Element2->NextInCol;
2569  *ElementAboveRow1 = Element2;
2570  Element2->NextInCol = ElementBelowRow1;
2571  }
2572  Element2->Row = Row1;
2573  }
2574  return;
2575 }
2576 
2577 
2578 
2579 
2580 
2581 
2582 
2583 /*
2584  * EXCHANGE TWO ELEMENTS IN A ROW
2585  *
2586  * Performs all required operations to exchange two elements in a row.
2587  * Those operations are: restring NextInRow pointers and swapping column
2588  * indexes in the MatrixElements.
2589  *
2590  * >>> Arguments:
2591  * Matrix <input> (MatrixPtr)
2592  * Pointer to the matrix.
2593  * Col1 <input> (int)
2594  * Col of left-most element to be exchanged.
2595  * Element1 <input> (ElementPtr)
2596  * Pointer to left-most element to be exchanged.
2597  * Col2 <input> (int)
2598  * Col of right-most element to be exchanged.
2599  * Element2 <input> (ElementPtr)
2600  * Pointer to right-most element to be exchanged.
2601  * Row <input> (int)
2602  * Row that exchange is to take place in.
2603  *
2604  * >>> Local variables:
2605  * ElementLeftOfCol1 (ElementPtr *)
2606  * Location of pointer which points to the element to the left of
2607  * Element1. This pointer is modified so that it points to correct
2608  * element on exit.
2609  * ElementLeftOfCol2 (ElementPtr *)
2610  * Location of pointer which points to the element to the left of
2611  * Element2. This pointer is modified so that it points to correct
2612  * element on exit.
2613  * ElementRightOfCol1 (ElementPtr)
2614  * Pointer to element right of Element1.
2615  * ElementRightOfCol2 (ElementPtr)
2616  * Pointer to element right of Element2.
2617  * pElement (ElementPtr)
2618  * Pointer used to traverse the row.
2619  */
2620 
2621 static void
2622 ExchangeRowElements( Matrix, Col1, Element1, Col2, Element2, Row )
2623 
2624 MatrixPtr Matrix;
2625 int Col1, Col2, Row;
2626 register ElementPtr Element1, Element2;
2627 {
2628 ElementPtr *ElementLeftOfCol1, *ElementLeftOfCol2;
2629 ElementPtr ElementRightOfCol1, ElementRightOfCol2;
2630 register ElementPtr pElement;
2631 
2632 /* Begin `ExchangeRowElements'. */
2633 /* Search to find the ElementLeftOfCol1. */
2634  ElementLeftOfCol1 = &(Matrix->FirstInRow[Row]);
2635  pElement = *ElementLeftOfCol1;
2636  while (pElement->Col < Col1)
2637  { ElementLeftOfCol1 = &(pElement->NextInRow);
2638  pElement = *ElementLeftOfCol1;
2639  }
2640  if (Element1 != NULL)
2641  { ElementRightOfCol1 = Element1->NextInRow;
2642  if (Element2 == NULL)
2643  {
2644 /* Element2 does not exist, move Element1 to right to Col2. */
2645  if ( ElementRightOfCol1 != NULL AND ElementRightOfCol1->Col < Col2 )
2646  {
2647 /* Element1 must be removed from linked list and moved. */
2648  *ElementLeftOfCol1 = ElementRightOfCol1;
2649 
2650 /* Search Row for Col2. */
2651  pElement = ElementRightOfCol1;
2652  do
2653  { ElementLeftOfCol2 = &(pElement->NextInRow);
2654  pElement = *ElementLeftOfCol2;
2655  } while (pElement != NULL AND pElement->Col < Col2);
2656 
2657 /* Place Element1 in Col2. */
2658  *ElementLeftOfCol2 = Element1;
2659  Element1->NextInRow = pElement;
2660  *ElementLeftOfCol1 =ElementRightOfCol1;
2661  }
2662  Element1->Col = Col2;
2663  }
2664  else
2665  {
2666 /* Element2 does exist, and the two elements must be exchanged. */
2667  if ( ElementRightOfCol1->Col == Col2)
2668  {
2669 /* Element2 is just right of Element1, exchange them. */
2670  Element1->NextInRow = Element2->NextInRow;
2671  Element2->NextInRow = Element1;
2672  *ElementLeftOfCol1 = Element2;
2673  }
2674  else
2675  {
2676 /* Element2 is not just right of Element1 and must be searched for. */
2677  pElement = ElementRightOfCol1;
2678  do
2679  { ElementLeftOfCol2 = &(pElement->NextInRow);
2680  pElement = *ElementLeftOfCol2;
2681  } while (pElement->Col < Col2);
2682 
2683  ElementRightOfCol2 = Element2->NextInRow;
2684 
2685 /* Switch Element1 and Element2. */
2686  *ElementLeftOfCol1 = Element2;
2687  Element2->NextInRow = ElementRightOfCol1;
2688  *ElementLeftOfCol2 = Element1;
2689  Element1->NextInRow = ElementRightOfCol2;
2690  }
2691  Element1->Col = Col2;
2692  Element2->Col = Col1;
2693  }
2694  }
2695  else
2696  {
2697 /* Element1 does not exist. */
2698  ElementRightOfCol1 = pElement;
2699 
2700 /* Find Element2. */
2701  if (ElementRightOfCol1->Col != Col2)
2702  { do
2703  { ElementLeftOfCol2 = &(pElement->NextInRow);
2704  pElement = *ElementLeftOfCol2;
2705  } while (pElement->Col < Col2);
2706 
2707  ElementRightOfCol2 = Element2->NextInRow;
2708 
2709 /* Move Element2 to Col1. */
2710  *ElementLeftOfCol2 = Element2->NextInRow;
2711  *ElementLeftOfCol1 = Element2;
2712  Element2->NextInRow = ElementRightOfCol1;
2713  }
2714  Element2->Col = Col1;
2715  }
2716  return;
2717 }
2718 
2719 
2720 
2721 
2722 
2723 
2724 
2725 
2726 
2727 
2728 
2729 /*
2730  * PERFORM ROW AND COLUMN ELIMINATION ON REAL MATRIX
2731  *
2732  * Eliminates a single row and column of the matrix and leaves single row of
2733  * the upper triangular matrix and a single column of the lower triangular
2734  * matrix in its wake. Uses Gauss's method.
2735  *
2736  * >>> Argument:
2737  * Matrix <input> (MatrixPtr)
2738  * Pointer to the matrix.
2739  * pPivot <input> (ElementPtr)
2740  * Pointer to the current pivot.
2741  *
2742  * >>> Local variables:
2743  * pLower (ElementPtr)
2744  * Points to matrix element in lower triangular column.
2745  * pSub (ElementPtr)
2746  * Points to elements in the reduced submatrix.
2747  * Row (int)
2748  * Row index.
2749  * pUpper (ElementPtr)
2750  * Points to matrix element in upper triangular row.
2751  *
2752  * >>> Possible errors:
2753  * spNO_MEMORY
2754  */
2755 
2756 static void
2758 
2759 MatrixPtr Matrix;
2760 register ElementPtr pPivot;
2761 {
2762 #if REAL
2763 register ElementPtr pSub;
2764 register int Row;
2765 register ElementPtr pLower, pUpper;
2766 extern ElementPtr CreateFillin();
2767 
2768 /* Begin `RealRowColElimination'. */
2769 
2770 /* Test for zero pivot. */
2771  if (ABS(pPivot->Real) == 0.0)
2772  { (void)MatrixIsSingular( Matrix, pPivot->Row );
2773  return;
2774  }
2775  pPivot->Real = 1.0 / pPivot->Real;
2776 
2777  pUpper = pPivot->NextInRow;
2778  while (pUpper != NULL)
2779  {
2780 /* Calculate upper triangular element. */
2781  pUpper->Real *= pPivot->Real;
2782 
2783  pSub = pUpper->NextInCol;
2784  pLower = pPivot->NextInCol;
2785  while (pLower != NULL)
2786  { Row = pLower->Row;
2787 
2788 /* Find element in row that lines up with current lower triangular element. */
2789  while (pSub != NULL AND pSub->Row < Row)
2790  pSub = pSub->NextInCol;
2791 
2792 /* Test to see if desired element was not found, if not, create fill-in. */
2793  if (pSub == NULL OR pSub->Row > Row)
2794  { pSub = CreateFillin( Matrix, Row, pUpper->Col );
2795  if (pSub == NULL)
2796  { Matrix->Error = spNO_MEMORY;
2797  return;
2798  }
2799  }
2800  pSub->Real -= pUpper->Real * pLower->Real;
2801  pSub = pSub->NextInCol;
2802  pLower = pLower->NextInCol;
2803  }
2804  pUpper = pUpper->NextInRow;
2805  }
2806  return;
2807 #endif /* REAL */
2808 }
2809 
2810 
2811 
2812 
2813 
2814 
2815 
2816 
2817 
2818 /*
2819  * PERFORM ROW AND COLUMN ELIMINATION ON COMPLEX MATRIX
2820  *
2821  * Eliminates a single row and column of the matrix and leaves single row of
2822  * the upper triangular matrix and a single column of the lower triangular
2823  * matrix in its wake. Uses Gauss's method.
2824  *
2825  * >>> Argument:
2826  * Matrix <input> (MatrixPtr)
2827  * Pointer to the matrix.
2828  * pPivot <input> (ElementPtr)
2829  * Pointer to the current pivot.
2830  *
2831  * >>> Local variables:
2832  * pLower (ElementPtr)
2833  * Points to matrix element in lower triangular column.
2834  * pSub (ElementPtr)
2835  * Points to elements in the reduced submatrix.
2836  * Row (int)
2837  * Row index.
2838  * pUpper (ElementPtr)
2839  * Points to matrix element in upper triangular row.
2840  *
2841  * Possible errors:
2842  * spNO_MEMORY
2843  */
2844 
2845 static void
2847 
2848 MatrixPtr Matrix;
2849 register ElementPtr pPivot;
2850 {
2851 #if spCOMPLEX
2852 register ElementPtr pSub;
2853 register int Row;
2854 register ElementPtr pLower, pUpper;
2856 
2857 /* Begin `ComplexRowColElimination'. */
2858 
2859 /* Test for zero pivot. */
2860  if (ELEMENT_MAG(pPivot) == 0.0)
2861  { (void)MatrixIsSingular( Matrix, pPivot->Row );
2862  return;
2863  }
2864  CMPLX_RECIPROCAL(*pPivot, *pPivot);
2865 
2866  pUpper = pPivot->NextInRow;
2867  while (pUpper != NULL)
2868  {
2869 /* Calculate upper triangular element. */
2870 /* Cmplx expr: *pUpper = *pUpper * (1.0 / *pPivot). */
2871  CMPLX_MULT_ASSIGN(*pUpper, *pPivot);
2872 
2873  pSub = pUpper->NextInCol;
2874  pLower = pPivot->NextInCol;
2875  while (pLower != NULL)
2876  { Row = pLower->Row;
2877 
2878 /* Find element in row that lines up with current lower triangular element. */
2879  while (pSub != NULL AND pSub->Row < Row)
2880  pSub = pSub->NextInCol;
2881 
2882 /* Test to see if desired element was not found, if not, create fill-in. */
2883  if (pSub == NULL OR pSub->Row > Row)
2884  { pSub = CreateFillin( Matrix, Row, pUpper->Col );
2885  if (pSub == NULL)
2886  { Matrix->Error = spNO_MEMORY;
2887  return;
2888  }
2889  }
2890 
2891 /* Cmplx expr: pElement -= *pUpper * pLower. */
2892  CMPLX_MULT_SUBT_ASSIGN(*pSub, *pUpper, *pLower);
2893  pSub = pSub->NextInCol;
2894  pLower = pLower->NextInCol;
2895  }
2896  pUpper = pUpper->NextInRow;
2897  }
2898  return;
2899 #endif /* spCOMPLEX */
2900 }
2901 
2902 
2903 
2904 
2905 
2906 /*
2907  * UPDATE MARKOWITZ NUMBERS
2908  *
2909  * Updates the Markowitz numbers after a row and column have been eliminated.
2910  * Also updates singleton count.
2911  *
2912  * >>> Argument:
2913  * Matrix <input> (MatrixPtr)
2914  * Pointer to the matrix.
2915  * pPivot <input> (ElementPtr)
2916  * Pointer to the current pivot.
2917  *
2918  * >>> Local variables:
2919  * Row (int)
2920  * Row index.
2921  * Col (int)
2922  * Column index.
2923  * ColPtr (ElementPtr)
2924  * Points to matrix element in upper triangular column.
2925  * RowPtr (ElementPtr)
2926  * Points to matrix element in lower triangular row.
2927  */
2928 
2929 static void
2931 
2932 MatrixPtr Matrix;
2934 {
2935 register int Row, Col;
2936 register ElementPtr ColPtr, RowPtr;
2937 register int *MarkoRow = Matrix->MarkowitzRow, *MarkoCol = Matrix->MarkowitzCol;
2938 double Product;
2939 
2940 /* Begin `UpdateMarkowitzNumbers'. */
2941 
2942 /* Update Markowitz numbers. */
2943  for (ColPtr = pPivot->NextInCol; ColPtr != NULL; ColPtr = ColPtr->NextInCol)
2944  { Row = ColPtr->Row;
2945  --MarkoRow[Row];
2946 
2947 /* Form Markowitz product while being cautious of overflows. */
2948  if ((MarkoRow[Row] > LARGEST_SHORT_INTEGER AND MarkoCol[Row] != 0) OR
2949  (MarkoCol[Row] > LARGEST_SHORT_INTEGER AND MarkoRow[Row] != 0))
2950  { Product = MarkoCol[Row] * MarkoRow[Row];
2951  if (Product >= LARGEST_LONG_INTEGER)
2952  Matrix->MarkowitzProd[Row] = LARGEST_LONG_INTEGER;
2953  else
2954  Matrix->MarkowitzProd[Row] = Product;
2955  }
2956  else Matrix->MarkowitzProd[Row] = MarkoRow[Row] * MarkoCol[Row];
2957  if (MarkoRow[Row] == 0)
2958  Matrix->Singletons++;
2959  }
2960 
2961  for (RowPtr = pPivot->NextInRow; RowPtr != NULL; RowPtr = RowPtr->NextInRow)
2962  { Col = RowPtr->Col;
2963  --MarkoCol[Col];
2964 
2965 /* Form Markowitz product while being cautious of overflows. */
2966  if ((MarkoRow[Col] > LARGEST_SHORT_INTEGER AND MarkoCol[Col] != 0) OR
2967  (MarkoCol[Col] > LARGEST_SHORT_INTEGER AND MarkoRow[Col] != 0))
2968  { Product = MarkoCol[Col] * MarkoRow[Col];
2969  if (Product >= LARGEST_LONG_INTEGER)
2970  Matrix->MarkowitzProd[Col] = LARGEST_LONG_INTEGER;
2971  else
2972  Matrix->MarkowitzProd[Col] = Product;
2973  }
2974  else Matrix->MarkowitzProd[Col] = MarkoRow[Col] * MarkoCol[Col];
2975  if ((MarkoCol[Col] == 0) AND (MarkoRow[Col] != 0))
2976  Matrix->Singletons++;
2977  }
2978  return;
2979 }
2980 
2981 
2982 
2983 
2984 
2985 
2986 
2987 
2988 /*
2989  * CREATE FILL-IN
2990  *
2991  * This routine is used to create fill-ins and splice them into the
2992  * matrix.
2993  *
2994  * >>> Returns:
2995  * Pointer to fill-in.
2996  *
2997  * >>> Arguments:
2998  * Matrix <input> (MatrixPtr)
2999  * Pointer to the matrix.
3000  * Col <input> (int)
3001  * Column index for element.
3002  * Row <input> (int)
3003  * Row index for element.
3004  *
3005  * >>> Local variables:
3006  * pElement (ElementPtr)
3007  * Pointer to an element in the matrix.
3008  * ppElementAbove (ElementPtr *)
3009  * This contains the address of the pointer to the element just above the
3010  * one being created. It is used to speed the search and it is updated
3011  * with address of the created element.
3012  *
3013  * >>> Possible errors:
3014  * spNO_MEMORY
3015  */
3016 
3017 static ElementPtr
3018 CreateFillin( Matrix, Row, Col )
3019 
3020 MatrixPtr Matrix;
3021 register int Row;
3022 int Col;
3023 {
3024 register ElementPtr pElement, *ppElementAbove;
3026 
3027 /* Begin `CreateFillin'. */
3028 
3029 /* Find Element above fill-in. */
3030  ppElementAbove = &Matrix->FirstInCol[Col];
3031  pElement = *ppElementAbove;
3032  while (pElement != NULL)
3033  { if (pElement->Row < Row)
3034  { ppElementAbove = &pElement->NextInCol;
3035  pElement = *ppElementAbove;
3036  }
3037  else break; /* while loop */
3038  }
3039 
3040 /* End of search, create the element. */
3041  pElement = spcCreateElement( Matrix, Row, Col, ppElementAbove, YES );
3042 
3043 /* Update Markowitz counts and products. */
3044  Matrix->MarkowitzProd[Row] = ++Matrix->MarkowitzRow[Row] *
3045  Matrix->MarkowitzCol[Row];
3046  if ((Matrix->MarkowitzRow[Row] == 1) AND (Matrix->MarkowitzCol[Row] != 0))
3047  Matrix->Singletons--;
3048  Matrix->MarkowitzProd[Col] = ++Matrix->MarkowitzCol[Col] *
3049  Matrix->MarkowitzRow[Col];
3050  if ((Matrix->MarkowitzRow[Col] != 0) AND (Matrix->MarkowitzCol[Col] == 1))
3051  Matrix->Singletons--;
3052 
3053  return pElement;
3054 }
3055 
3056 
3057 
3058 
3059 
3060 
3061 
3062 
3063 /*
3064  * ZERO PIVOT ENCOUNTERED
3065  *
3066  * This routine is called when a singular matrix is found. It then
3067  * records the current row and column and exits.
3068  *
3069  * >>> Returned:
3070  * The error code spSINGULAR or spZERO_DIAG is returned.
3071  *
3072  * >>> Arguments:
3073  * Matrix <input> (MatrixPtr)
3074  * Pointer to matrix.
3075  * Step <input> (int)
3076  * Index of diagonal that is zero.
3077  */
3078 
3079 static int
3080 MatrixIsSingular( Matrix, Step )
3081 
3082 MatrixPtr Matrix;
3083 int Step;
3084 {
3085 /* Begin `MatrixIsSingular'. */
3086 
3087  Matrix->SingularRow = Matrix->IntToExtRowMap[ Step ];
3088  Matrix->SingularCol = Matrix->IntToExtColMap[ Step ];
3089  return (Matrix->Error = spSINGULAR);
3090 }
3091 
3092 
3093 static int
3094 ZeroPivot( Matrix, Step )
3095 
3096 MatrixPtr Matrix;
3097 int Step;
3098 {
3099 /* Begin `ZeroPivot'. */
3100 
3101  Matrix->SingularRow = Matrix->IntToExtRowMap[ Step ];
3102  Matrix->SingularCol = Matrix->IntToExtColMap[ Step ];
3103  return (Matrix->Error = spZERO_DIAG);
3104 }
3105 
3106 
3107 
3108 
3109 
3110 
3111 #if (ANNOTATE == FULL)
3112 
3113 /*
3114  *
3115  * WRITE STATUS
3116  *
3117  * Write a summary of important variables to standard output.
3118  */
3119 
3120 static void
3121 WriteStatus( Matrix, Step )
3122 
3123 MatrixPtr Matrix;
3124 int Step;
3125 {
3126 int I;
3127 
3128 /* Begin `WriteStatus'. */
3129 
3130  printf("Step = %1d ", Step);
3131  printf("Pivot found at %1d,%1d using ", Matrix->PivotsOriginalRow,
3132  Matrix->PivotsOriginalCol);
3133  switch(Matrix->PivotSelectionMethod)
3134  { case 's': printf("SearchForSingleton\n"); break;
3135  case 'q': printf("QuicklySearchDiagonal\n"); break;
3136  case 'd': printf("SearchDiagonal\n"); break;
3137  case 'e': printf("SearchEntireMatrix\n"); break;
3138  }
3139 
3140  printf("MarkowitzRow = ");
3141  for (I = 1; I <= Matrix->Size; I++)
3142  printf("%2d ", Matrix->MarkowitzRow[I]);
3143  printf("\n");
3144 
3145  printf("MarkowitzCol = ");
3146  for (I = 1; I <= Matrix->Size; I++)
3147  printf("%2d ", Matrix->MarkowitzCol[I]);
3148  printf("\n");
3149 
3150  printf("MarkowitzProduct = ");
3151  for (I = 1; I <= Matrix->Size; I++)
3152  printf("%2d ", Matrix->MarkowitzProd[I]);
3153  printf("\n");
3154 
3155  printf("Singletons = %2d\n", Matrix->Singletons);
3156 
3157  printf("IntToExtRowMap = ");
3158  for (I = 1; I <= Matrix->Size; I++)
3159  printf("%2d ", Matrix->IntToExtRowMap[I]);
3160  printf("\n");
3161 
3162  printf("IntToExtColMap = ");
3163  for (I = 1; I <= Matrix->Size; I++)
3164  printf("%2d ", Matrix->IntToExtColMap[I]);
3165  printf("\n");
3166 
3167  printf("ExtToIntRowMap = ");
3168  for (I = 1; I <= Matrix->ExtSize; I++)
3169  printf("%2d ", Matrix->ExtToIntRowMap[I]);
3170  printf("\n");
3171 
3172  printf("ExtToIntColMap = ");
3173  for (I = 1; I <= Matrix->ExtSize; I++)
3174  printf("%2d ", Matrix->ExtToIntColMap[I]);
3175  printf("\n\n");
3176 
3177 /* spPrint((char *)Matrix, NO, YES); */
3178 
3179  return;
3180 
3181 }
3182 #endif /* ANNOTATE == FULL */
BOOLEAN Partitioned
Definition: spdefs.h:848
#define CMPLX_MULT_ASSIGN(to, from)
Definition: spdefs.h:241
static RealNumber FindBiggestInColExclude()
void spcRowExchange(MatrixPtr Matrix, int Row1, int Row2)
Definition: spfactor.c:2271
RealNumber RelThreshold
Definition: spdefs.h:853
#define spDEFAULT_PARTITION
Definition: spmatrix.h:177
#define ALLOC(type, number)
Definition: spdefs.h:433
#define CMPLX_ASSIGN(to, from)
Definition: spdefs.h:165
int * MarkowitzRow
Definition: spdefs.h:842
int * MarkowitzCol
Definition: spdefs.h:843
#define spINDIRECT_PARTITION
Definition: spmatrix.h:179
static void CountMarkowitz()
#define MAX(a, b)
Definition: spdefs.h:135
#define NO
Definition: spdefs.h:113
int Size
Definition: spdefs.h:859
#define BOOLEAN
Definition: spdefs.h:112
void spcColExchange(MatrixPtr Matrix, int Col1, int Col2)
Definition: spfactor.c:2373
static RealNumber FindLargestInCol()
#define spDIRECT_PARTITION
Definition: spmatrix.h:178
BOOLEAN * DoRealDirect
Definition: spdefs.h:827
int SingularRow
Definition: spdefs.h:857
#define spSINGULAR
Definition: spmatrix.h:104
#define spOKAY
Definition: spmatrix.h:101
#define spAUTO_PARTITION
Definition: spmatrix.h:180
#define spFATAL
Definition: spmatrix.h:108
RealNumber Real
Definition: spdefs.h:539
static int ZeroPivot()
long * MarkowitzProd
Definition: spdefs.h:844
This document describes the JSPICE3 Josephson junction model I derivation of the model The expression for the junction current is J
Definition: model.doc:9
static int MatrixIsSingular()
spREAL * RealVector
Definition: spdefs.h:458
#define IS_SPARSE(matrix)
Definition: spdefs.h:125
static void ExchangeRowsAndCols()
static void ExchangeRowElements()
#define ELEMENT_MAG(ptr)
Definition: spdefs.h:161
static int FactorComplexMatrix()
#define CMPLX_MULT_SUBT_ASSIGN(to, from_a, from_b)
Definition: spdefs.h:297
struct MatrixElement * NextInCol
Definition: spdefs.h:547
BOOLEAN Factored
Definition: spdefs.h:833
static ElementPtr SearchEntireMatrix()
BOOLEAN NeedsOrdering
Definition: spdefs.h:846
spREAL * Element2
Definition: spmatrix.h:282
#define spSMALL_PIVOT
Definition: spmatrix.h:102
spREAL * Element1
Definition: spmatrix.h:281
RealNumber AbsThreshold
Definition: spdefs.h:820
static void RealRowColElimination()
ElementPtr spcCreateElement()
#define IS_VALID(matrix)
Definition: spdefs.h:127
ASSERT(IS_VALID(Matrix) AND IS_FACTORED(Matrix))
static ElementPtr SearchDiagonal()
#define NULL
Definition: spdefs.h:121
#define OR
Definition: fteparse.h:93
register ElementPtr pElement
Definition: spsolve.c:158
register int Size
Definition: spsolve.c:163
static void ComplexRowColElimination()
#define CMPLX_1_NORM(a)
Definition: spdefs.h:188
static void UpdateMarkowitzNumbers()
static ElementPtr SearchForPivot()
ElementPtr spcFindElementInCol()
void spcCreateInternalVectors(MatrixPtr Matrix)
Definition: spfactor.c:772
static void ExchangeColElements()
void spcLinkRows()
#define ABS(a)
Definition: spdefs.h:139
int Error
Definition: spdefs.h:829
BOOLEAN Complex
Definition: spdefs.h:823
RealVector Intermediate
Definition: spdefs.h:838
static ElementPtr SearchForSingleton()
#define SWAP(type, a, b)
Definition: spdefs.h:145
BOOLEAN RowsLinked
Definition: spdefs.h:855
while(TDesc->tSucc!=NULL)
Definition: cd.c:1335
static void WriteStatus()
spREAL RealNumber
Definition: spdefs.h:458
#define YES
Definition: spdefs.h:114
BOOLEAN InternalVectorsAllocated
Definition: spdefs.h:839
RealVector RHS
Definition: spsolve.c:157
int spOrderAndFactor(char *eMatrix, RHS, RelThreshold, AbsThreshold, BOOLEAN DiagPivoting)
Definition: spfactor.c:222
struct MatrixElement * NextInRow
Definition: spdefs.h:546
ArrayOfElementPtrs Diag
Definition: spdefs.h:825
#define NOT
Definition: fteparse.h:94
BOOLEAN Reordered
Definition: spdefs.h:854
register int I
Definition: spsolve.c:163
struct MatrixFrame * MatrixPtr
Definition: spdefs.h:871
#define CMPLX_MULT(to, from_a, from_b)
Definition: spdefs.h:233
int MaxRowCountInLowerTri
Definition: spdefs.h:845
static ElementPtr CreateFillin()
ElementPtr pPivot
Definition: spsolve.c:164
#define spNO_MEMORY
Definition: spmatrix.h:105
BOOLEAN * DoCmplxDirect
Definition: spdefs.h:826
int spFactor(char *eMatrix)
Definition: spfactor.c:364
ArrayOfElementPtrs FirstInCol
Definition: spdefs.h:835
#define spZERO_DIAG
Definition: spmatrix.h:103
void spPartition(char *eMatrix, int Mode)
Definition: spfactor.c:623
static ElementPtr QuicklySearchDiagonal()
#define CMPLX_RECIPROCAL(to, den)
Definition: spdefs.h:367
#define AND
Definition: fteparse.h:92
static void MarkowitzProducts()