📄 spfactor.c
字号:
* A local version of Matrix->Singletons.
* pMarkowitzProduct (long *)
* Pointer that points into MarkowitzProduct array. It is used to quickly
* access successive Markowitz products.
*/
static ElementPtr
SearchForSingleton(
MatrixPtr Matrix,
int Step
)
{
register ElementPtr ChosenPivot;
register int I;
register long *pMarkowitzProduct;
int Singletons;
RealNumber PivotMag;
/* Begin `SearchForSingleton'. */
/* Initialize pointer that is to scan through MarkowitzProduct vector. */
pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+1]);
Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step];
/* Decrement the count of available singletons, on the assumption that an
* acceptable one will be found. */
Singletons = Matrix->Singletons--;
/*
* Assure that following while loop will always terminate, this is just
* preventive medicine, if things are working right this should never
* be needed.
*/
Matrix->MarkowitzProd[Step-1] = 0;
while (Singletons-- > 0)
{
/* Singletons exist, find them. */
/*
* This is tricky. Am using a pointer to sequentially step through the
* MarkowitzProduct array. Search terminates when singleton (Product = 0)
* is found. Note that the conditional in the while statement
* ( *pMarkowitzProduct ) is true as long as the MarkowitzProduct is not
* equal to zero. The row (and column) index on the diagonal is then
* calculated by subtracting the pointer to the Markowitz product of
* the first diagonal from the pointer to the Markowitz product of the
* desired element, the singleton.
*
* Search proceeds from the end (high row and column numbers) to the
* beginning (low row and column numbers) so that rows and columns with
* large Markowitz products will tend to be move to the bottom of the
* matrix. However, choosing Diag[Step] is desirable because it would
* require no row and column interchanges, so inspect it first by
* putting its Markowitz product at the end of the MarkowitzProd
* vector.
*/
while ( *pMarkowitzProduct-- )
{ /*
* N bottles of beer on the wall;
* N bottles of beer.
* you take one down and pass it around;
* N-1 bottles of beer on the wall.
*/
}
I = pMarkowitzProduct - Matrix->MarkowitzProd + 1;
/* Assure that I is valid. */
if (I < Step) break; /* while (Singletons-- > 0) */
if (I > Matrix->Size) I = Step;
/* Singleton has been found in either/both row or/and column I. */
if ((ChosenPivot = Matrix->Diag[I]) != NULL)
{
/* Singleton lies on the diagonal. */
PivotMag = ELEMENT_MAG(ChosenPivot);
if
( PivotMag > Matrix->AbsThreshold AND
PivotMag > Matrix->RelThreshold *
FindBiggestInColExclude( Matrix, ChosenPivot, Step )
) return ChosenPivot;
}
else
{
/* Singleton does not lie on diagonal, find it. */
if (Matrix->MarkowitzCol[I] == 0)
{ ChosenPivot = Matrix->FirstInCol[I];
while ((ChosenPivot != NULL) AND (ChosenPivot->Row < Step))
ChosenPivot = ChosenPivot->NextInCol;
if (ChosenPivot == NULL)
{ /* Reduced column has no elements, matrix is singular. */
break;
}
PivotMag = ELEMENT_MAG( ChosenPivot );
if
( PivotMag > Matrix->AbsThreshold AND
PivotMag > Matrix->RelThreshold *
FindBiggestInColExclude( Matrix, ChosenPivot,
Step )
) return ChosenPivot;
else
{ if (Matrix->MarkowitzRow[I] == 0)
{ ChosenPivot = Matrix->FirstInRow[I];
while((ChosenPivot != NULL) AND (ChosenPivot->Col<Step))
ChosenPivot = ChosenPivot->NextInRow;
if (ChosenPivot == NULL)
{/* Reduced row has no elements, matrix is singular. */
break;
}
PivotMag = ELEMENT_MAG(ChosenPivot);
if
( PivotMag > Matrix->AbsThreshold AND
PivotMag > Matrix->RelThreshold *
FindBiggestInColExclude( Matrix,
ChosenPivot,
Step )
) return ChosenPivot;
}
}
}
else
{ ChosenPivot = Matrix->FirstInRow[I];
while ((ChosenPivot != NULL) AND (ChosenPivot->Col < Step))
ChosenPivot = ChosenPivot->NextInRow;
if (ChosenPivot == NULL)
{ /* Reduced row has no elements, matrix is singular. */
break;
}
PivotMag = ELEMENT_MAG(ChosenPivot);
if
( PivotMag > Matrix->AbsThreshold AND
PivotMag > Matrix->RelThreshold *
FindBiggestInColExclude( Matrix, ChosenPivot,
Step )
) return ChosenPivot;
}
}
/* Singleton not acceptable (too small), try another. */
} /* end of while(lSingletons>0) */
/*
* All singletons were unacceptable. Restore Matrix->Singletons count.
* Initial assumption that an acceptable singleton would be found was wrong.
*/
Matrix->Singletons++;
return NULL;
}
#if DIAGONAL_PIVOTING
#if MODIFIED_MARKOWITZ
/*
* QUICK SEARCH OF DIAGONAL FOR PIVOT WITH MODIFIED MARKOWITZ CRITERION
*
* Searches the diagonal looking for the best pivot. For a pivot to be
* acceptable it must be larger than the pivot RelThreshold times the largest
* element in its reduced column. Among the acceptable diagonals, the
* one with the smallest MarkowitzProduct is sought. Search terminates
* early if a diagonal is found with a MarkowitzProduct of one and its
* magnitude is larger than the other elements in its row and column.
* Since its MarkowitzProduct is one, there is only one other element in
* both its row and column, and, as a condition for early termination,
* these elements must be located symmetricly in the matrix. If a tie
* occurs between elements of equal MarkowitzProduct, then the element with
* the largest ratio between its magnitude and the largest element in its
* column is used. The search will be terminated after a given number of
* ties have occurred and the best (largest ratio) of the tied element will
* be used as the pivot. The number of ties that will trigger an early
* termination is MinMarkowitzProduct * TIES_MULTIPLIER.
*
* >>> Returned:
* A pointer to the diagonal element chosen to be pivot. If no diagonal is
* acceptable, a NULL is returned.
*
* >>> Arguments:
* Step <input> (int)
* Index of the diagonal currently being eliminated.
*
* >>> Local variables:
* ChosenPivot (ElementPtr)
* Pointer to the element that has been chosen to be the pivot.
* LargestOffDiagonal (RealNumber)
* Magnitude of the largest of the off-diagonal terms associated with
* a diagonal with MarkowitzProduct equal to one.
* Magnitude (RealNumber)
* Absolute value of diagonal element.
* MaxRatio (RealNumber)
* Among the elements tied with the smallest Markowitz product, MaxRatio
* is the best (smallest) ratio of LargestInCol to the diagonal Magnitude
* found so far. The smaller the ratio, the better numerically the
* element will be as pivot.
* MinMarkowitzProduct (long)
* Smallest Markowitz product found of pivot candidates that lie along
* diagonal.
* NumberOfTies (int)
* A count of the number of Markowitz ties that have occurred at current
* MarkowitzProduct.
* pDiag (ElementPtr)
* Pointer to current diagonal element.
* pMarkowitzProduct (long *)
* Pointer that points into MarkowitzProduct array. It is used to quickly
* access successive Markowitz products.
* Ratio (RealNumber)
* For the current pivot candidate, Ratio is the ratio of the largest
* element in its column (excluding itself) to its magnitude.
* TiedElements (ElementPtr[])
* Array of pointers to the elements with the minimum Markowitz
* product.
* pOtherInCol (ElementPtr)
* When there is only one other element in a column other than the
* diagonal, pOtherInCol is used to point to it. Used when Markowitz
* product is to determine if off diagonals are placed symmetricly.
* pOtherInRow (ElementPtr)
* When there is only one other element in a row other than the diagonal,
* pOtherInRow is used to point to it. Used when Markowitz product is
* to determine if off diagonals are placed symmetricly.
*/
static ElementPtr
QuicklySearchDiagonal(
MatrixPtr Matrix,
int Step
)
{
register long MinMarkowitzProduct, *pMarkowitzProduct;
register ElementPtr pDiag, pOtherInRow, pOtherInCol;
int I, NumberOfTies;
ElementPtr ChosenPivot, TiedElements[MAX_MARKOWITZ_TIES + 1];
RealNumber Magnitude, LargestInCol, Ratio, MaxRatio;
RealNumber LargestOffDiagonal;
RealNumber FindBiggestInColExclude();
/* Begin `QuicklySearchDiagonal'. */
NumberOfTies = -1;
MinMarkowitzProduct = LARGEST_LONG_INTEGER;
pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+2]);
Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step];
/* Assure that following while loop will always terminate. */
Matrix->MarkowitzProd[Step-1] = -1;
/*
* This is tricky. Am using a pointer in the inner while loop to
* sequentially step through the MarkowitzProduct array. Search
* terminates when the Markowitz product of zero placed at location
* Step-1 is found. The row (and column) index on the diagonal is then
* calculated by subtracting the pointer to the Markowitz product of
* the first diagonal from the pointer to the Markowitz product of the
* desired element. The outer for loop is infinite, broken by using
* break.
*
* Search proceeds from the end (high row and column numbers) to the
* beginning (low row and column numbers) so that rows and columns with
* large Markowitz products will tend to be move to the bottom of the
* matrix. However, choosing Diag[Step] is desirable because it would
* require no row and column interchanges, so inspect it first by
* putting its Markowitz product at the end of the MarkowitzProd
* vector.
*/
for(;;) /* Endless for loop. */
{ while (MinMarkowitzProduct < *(--pMarkowitzProduct))
{ /*
* N bottles of beer on the wall;
* N bottles of beer.
* You take one down and pass it around;
* N-1 bottles of beer on the wall.
*/
}
I = pMarkowitzProduct - Matrix->MarkowitzProd;
/* Assure that I is valid; if I < Step, terminate search. */
if (I < Step) break; /* Endless for loop */
if (I > Matrix->Size) I = Step;
if ((pDiag = Matrix->Diag[I]) == NULL)
continue; /* Endless for loop */
if ((Magnitude = ELEMENT_MAG(pDiag)) <= Matrix->AbsThreshold)
continue; /* Endless for loop */
if (*pMarkowitzProduct == 1)
{
/* Case where only one element exists in row and column other than diagonal. */
/* Find off diagonal elements. */
pOtherInRow = pDiag->NextInRow;
pOtherInCol = pDiag->NextInCol;
if (pOtherInRow == NULL AND pOtherInCol == NULL)
{ pOtherInRow = Matrix->FirstInRow[I];
while(pOtherInRow != NULL)
{ if (pOtherInRow->Col >= Step AND pOtherInRow->Col != I)
break;
pOtherInRow = pOtherInRow->NextInRow;
}
pOtherInCol = Matrix->FirstInCol[I];
while(pOtherInCol != NULL)
{ if (pOtherInCol->Row >= Step AND pOtherInCol->Row != I)
break;
pOtherInCol = pOtherInCol->NextInCol;
}
}
/* Accept diagonal as pivot if diagonal is larger than off diagonals and the
* off diagonals are placed symmetricly. */
if (pOtherInRow != NULL AND pOtherInCol != NULL)
{ if (pOtherInRow->Col == pOtherInCol->Row)
{ LargestOffDiagonal = MAX(ELEMENT_MAG(pOtherInRow),
ELEMENT_MAG(pOtherInCol));
if (Magnitude >= LargestOffDiagonal)
{
/* Accept pivot, it is unlikely to contribute excess error. */
return pDiag;
}
}
}
}
if (*pMarkowitzProduct < MinMarkowitzProduct)
{
/* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */
TiedElements[0] = pDiag;
MinMarkowitzProduct = *pMarkowitzProduct;
NumberOfTies = 0;
}
else
{
/* This case handles Markowitz ties. */
if (NumberOfTies < MAX_MARKOWITZ_TIES)
{ TiedElements[++NumberOfTies] = pDiag;
if (NumberOfTies >= MinMarkowitzProduct * TIES_MULTIPLIER)
break; /* Endless for loop */
}
}
} /* End of endless for loop. */
/* Test to see if any element was chosen as a pivot candidate. */
if (NumberOfTies < 0)
return NULL;
/* Determine which of tied elements is best numerically. */
ChosenPivot = NULL;
MaxRatio = 1.0 / Matrix->RelThreshold;
for (I = 0; I <= NumberOfTies; I++)
{ pDiag = TiedElements[I];
Magnitude = ELEMENT_MAG(pDiag);
LargestInCol = FindBiggestInColExclude( Matrix, pDiag, Step );
Ratio = LargestInCol / Magnitude;
if (Ratio < MaxRatio)
{ ChosenPivot = pDiag;
MaxRatio = Ratio;
}
}
return ChosenPivot;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -