📄 spfactor.c
字号:
* 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. * A local version of Matrix->Singletons. * pMarkowitzProduct (long *) * Pointer that points into MarkowitzProduct array. It is used to quickly * access successive Markowitz products. */static ElementPtrSearchForSingleton( Matrix, Step )MatrixPtr Matrix;int Step;{register ElementPtr ChosenPivot;register int I;register long *pMarkowitzProduct;int Singletons;RealNumber PivotMag, FindBiggestInColExclude();/* 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 ElementPtrQuicklySearchDiagonal( Matrix, Step )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 + -