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