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