📄 spfactor.c
字号:
* spNO_MEMORY
*/
void
spcCreateInternalVectors( MatrixPtr Matrix )
{
int Size;
/* Begin `spcCreateInternalVectors'. */
/* Create Markowitz arrays. */
Size= Matrix->Size;
if (Matrix->MarkowitzRow == NULL)
{ if (( Matrix->MarkowitzRow = ALLOC(int, Size+1)) == NULL)
Matrix->Error = spNO_MEMORY;
}
if (Matrix->MarkowitzCol == NULL)
{ if (( Matrix->MarkowitzCol = ALLOC(int, Size+1)) == NULL)
Matrix->Error = spNO_MEMORY;
}
if (Matrix->MarkowitzProd == NULL)
{ if (( Matrix->MarkowitzProd = ALLOC(long, Size+2)) == NULL)
Matrix->Error = spNO_MEMORY;
}
/* Create DoDirect vectors for use in spFactor(). */
#if REAL
if (Matrix->DoRealDirect == NULL)
{ if (( Matrix->DoRealDirect = ALLOC(BOOLEAN, Size+1)) == NULL)
Matrix->Error = spNO_MEMORY;
}
#endif
#if spCOMPLEX
if (Matrix->DoCmplxDirect == NULL)
{ if (( Matrix->DoCmplxDirect = ALLOC(BOOLEAN, Size+1)) == NULL)
Matrix->Error = spNO_MEMORY;
}
#endif
/* Create Intermediate vectors for use in MatrixSolve. */
#if spCOMPLEX
if (Matrix->Intermediate == NULL)
{ if ((Matrix->Intermediate = ALLOC(RealNumber,2*(Size+1))) == NULL)
Matrix->Error = spNO_MEMORY;
}
#else
if (Matrix->Intermediate == NULL)
{ if ((Matrix->Intermediate = ALLOC(RealNumber, Size+1)) == NULL)
Matrix->Error = spNO_MEMORY;
}
#endif
if (Matrix->Error != spNO_MEMORY)
Matrix->InternalVectorsAllocated = YES;
return;
}
/*
* COUNT MARKOWITZ
*
* Scans Matrix to determine the Markowitz counts for each row and column.
*
* >>> Arguments:
* Matrix <input> (MatrixPtr)
* Pointer to matrix.
* RHS <input> (RealVector)
* Representative right-hand side vector that is used to determine
* pivoting order when the right hand side vector is sparse. If
* RHS is a NULL pointer then the RHS vector is assumed to be full
* and it is not used when determining the pivoting order.
* Step <input> (int)
* Index of the diagonal currently being eliminated.
*
* >>> Local variables:
* Count (int)
* Temporary counting variable.
* ExtRow (int)
* The external row number that corresponds to I.
* pElement (ElementPtr)
* Pointer to matrix elements.
* Size (int)
* The size of the matrix.
*/
static void
CountMarkowitz(
MatrixPtr Matrix,
register RealVector RHS,
int Step
)
{
register int Count, I, Size = Matrix->Size;
register ElementPtr pElement;
int ExtRow;
/* Begin `CountMarkowitz'. */
/* Correct array pointer for ARRAY_OFFSET. */
#if NOT ARRAY_OFFSET
#if spSEPARATED_COMPLEX_VECTORS OR NOT spCOMPLEX
if (RHS != NULL) --RHS;
#else
if (RHS != NULL)
{ if (Matrix->Complex) RHS -= 2;
else --RHS;
}
#endif
#endif
/* Generate MarkowitzRow Count for each row. */
for (I = Step; I <= Size; I++)
{
/* Set Count to -1 initially to remove count due to pivot element. */
Count = -1;
pElement = Matrix->FirstInRow[I];
while (pElement != NULL AND pElement->Col < Step)
pElement = pElement->NextInRow;
while (pElement != NULL)
{ Count++;
pElement = pElement->NextInRow;
}
/* Include nonzero elements in the RHS vector. */
ExtRow = Matrix->IntToExtRowMap[I];
#if spSEPARATED_COMPLEX_VECTORS OR NOT spCOMPLEX
if (RHS != NULL)
if (RHS[ExtRow] != 0.0) Count++;
#else
if (RHS != NULL)
{ if (Matrix->Complex)
{ if ((RHS[2*ExtRow] != 0.0) OR (RHS[2*ExtRow+1] != 0.0))
Count++;
}
else if (RHS[I] != 0.0) Count++;
}
#endif
Matrix->MarkowitzRow[I] = Count;
}
/* Generate the MarkowitzCol count for each column. */
for (I = Step; I <= Size; I++)
{
/* Set Count to -1 initially to remove count due to pivot element. */
Count = -1;
pElement = Matrix->FirstInCol[I];
while (pElement != NULL AND pElement->Row < Step)
pElement = pElement->NextInCol;
while (pElement != NULL)
{ Count++;
pElement = pElement->NextInCol;
}
Matrix->MarkowitzCol[I] = Count;
}
return;
}
/*
* MARKOWITZ PRODUCTS
*
* Calculates MarkowitzProduct for each diagonal element from the Markowitz
* counts.
*
* >>> Arguments:
* Matrix <input> (MatrixPtr)
* Pointer to matrix.
* Step <input> (int)
* Index of the diagonal currently being eliminated.
*
* >>> Local Variables:
* pMarkowitzProduct (long *)
* Pointer that points into MarkowitzProduct array. Is used to
* sequentially access entries quickly.
* pMarkowitzRow (int *)
* Pointer that points into MarkowitzRow array. Is used to sequentially
* access entries quickly.
* pMarkowitzCol (int *)
* Pointer that points into MarkowitzCol array. Is used to sequentially
* access entries quickly.
* Product (long)
* Temporary storage for Markowitz product./
* Size (int)
* The size of the matrix.
*/
static void
MarkowitzProducts(
MatrixPtr Matrix,
int Step
)
{
register int I, *pMarkowitzRow, *pMarkowitzCol;
register long Product, *pMarkowitzProduct;
register int Size = Matrix->Size;
double fProduct;
/* Begin `MarkowitzProducts'. */
Matrix->Singletons = 0;
pMarkowitzProduct = &(Matrix->MarkowitzProd[Step]);
pMarkowitzRow = &(Matrix->MarkowitzRow[Step]);
pMarkowitzCol = &(Matrix->MarkowitzCol[Step]);
for (I = Step; I <= Size; I++)
{
/* If chance of overflow, use real numbers. */
if ((*pMarkowitzRow > LARGEST_SHORT_INTEGER AND *pMarkowitzCol != 0) OR
(*pMarkowitzCol > LARGEST_SHORT_INTEGER AND *pMarkowitzRow != 0))
{ fProduct = (double)(*pMarkowitzRow++) * (double)(*pMarkowitzCol++);
if (fProduct >= LARGEST_LONG_INTEGER)
*pMarkowitzProduct++ = LARGEST_LONG_INTEGER;
else
*pMarkowitzProduct++ = (long)fProduct;
}
else
{ Product = *pMarkowitzRow++ * *pMarkowitzCol++;
if ((*pMarkowitzProduct++ = Product) == 0)
Matrix->Singletons++;
}
}
return;
}
/*
* SEARCH FOR BEST PIVOT
*
* Performs a search to determine the element with the lowest Markowitz
* Product that is also acceptable. An acceptable element is one that is
* larger than the AbsThreshold and at least as large as RelThreshold times
* the largest element in the same column. The first step is to look for
* singletons if any exist. If none are found, then all the diagonals are
* searched. The diagonal is searched once quickly using the assumption that
* elements on the diagonal are large compared to other elements in their
* column, and so the pivot can be chosen only on the basis of the Markowitz
* criterion. After a element has been chosen to be pivot on the basis of
* its Markowitz product, it is checked to see if it is large enough.
* Waiting to the end of the Markowitz search to check the size of a pivot
* candidate saves considerable time, but is not guaranteed to find an
* acceptable pivot. Thus if unsuccessful a second pass of the diagonal is
* made. This second pass checks to see if an element is large enough during
* the search, not after it. If still no acceptable pivot candidate has
* been found, the search expands to cover the entire matrix.
*
* >>> Returned:
* A pointer to the element chosen to be pivot. If every element in the
* matrix is zero, then NULL is returned.
*
* >>> Arguments:
* Matrix <input> (MatrixPtr)
* Pointer to matrix.
* Step <input> (int)
* The row and column number of the beginning of the reduced submatrix.
*
* >>> Local variables:
* ChosenPivot (ElementPtr)
* Pointer to element that has been chosen to be the pivot.
*
* >>> Possible errors:
* spSINGULAR
* spSMALL_PIVOT
*/
static ElementPtr
SearchForPivot(
MatrixPtr Matrix,
int Step,
BOOLEAN DiagPivoting
)
{
register ElementPtr ChosenPivot;
/* Begin `SearchForPivot'. */
/* If singletons exist, look for an acceptable one to use as pivot. */
if (Matrix->Singletons)
{ ChosenPivot = SearchForSingleton( Matrix, Step );
if (ChosenPivot != NULL)
{ Matrix->PivotSelectionMethod = 's';
return ChosenPivot;
}
}
#if DIAGONAL_PIVOTING
if (DiagPivoting)
{
/*
* Either no singletons exist or they weren't acceptable. Take quick first
* pass at searching diagonal. First search for element on diagonal of
* remaining submatrix with smallest Markowitz product, then check to see
* if it okay numerically. If not, QuicklySearchDiagonal fails.
*/
ChosenPivot = QuicklySearchDiagonal( Matrix, Step );
if (ChosenPivot != NULL)
{ Matrix->PivotSelectionMethod = 'q';
return ChosenPivot;
}
/*
* Quick search of diagonal failed, carefully search diagonal and check each
* pivot candidate numerically before even tentatively accepting it.
*/
ChosenPivot = SearchDiagonal( Matrix, Step );
if (ChosenPivot != NULL)
{ Matrix->PivotSelectionMethod = 'd';
return ChosenPivot;
}
}
#endif /* DIAGONAL_PIVOTING */
/* No acceptable pivot found yet, search entire matrix. */
ChosenPivot = SearchEntireMatrix( Matrix, Step );
Matrix->PivotSelectionMethod = 'e';
return ChosenPivot;
}
/*
* SEARCH FOR SINGLETON TO USE AS PIVOT
*
* Performs a search to find a singleton to use as the pivot. The
* first acceptable singleton is used. A singleton is acceptable if
* it is larger in magnitude than the AbsThreshold and larger
* than RelThreshold times the largest of any other elements in the same
* column. It may seem that a singleton need not satisfy the
* relative threshold criterion, however it is necessary to prevent
* excessive growth in the RHS from resulting in overflow during the
* forward and backward substitution. A singleton does not need to
* be on the diagonal to be selected.
*
* >>> Returned:
* A pointer to the singleton chosen to be pivot. In no singleton is
* acceptable, return NULL.
*
* >>> Arguments:
* Matrix <input> (MatrixPtr)
* Pointer to matrix.
* Step <input> (int)
* Index of the diagonal currently being eliminated.
*
* >>> Local variables:
* ChosenPivot (ElementPtr)
* Pointer to element that has been chosen to be the pivot.
* PivotMag (RealNumber)
* Magnitude of ChosenPivot.
* Singletons (int)
* The count of the number of singletons that can be used as pivots.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -