📄 spfactor.c
字号:
{ /* Singleton does not lie on diagonal, find it. */ if (Matrix->MarkowitzCol[I] == 0) { ChosenPivot = Matrix->FirstInCol[I]; while ((ChosenPivot != NULL) && (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 && PivotMag > Matrix->RelThreshold * FindBiggestInColExclude( Matrix, ChosenPivot, Step ) ) return ChosenPivot; else { if (Matrix->MarkowitzRow[I] == 0) { ChosenPivot = Matrix->FirstInRow[I]; while((ChosenPivot != NULL) && (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 && PivotMag > Matrix->RelThreshold * FindBiggestInColExclude( Matrix, ChosenPivot, Step ) ) return ChosenPivot; } } } else { ChosenPivot = Matrix->FirstInRow[I]; while ((ChosenPivot != NULL) && (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 && 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;{long MinMarkowitzProduct, *pMarkowitzProduct; 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)strchr 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 && pOtherInCol == NULL) { pOtherInRow = Matrix->FirstInRow[I]; while(pOtherInRow != NULL) { if (pOtherInRow->Col >= Step && pOtherInRow->Col != I) break; pOtherInRow = pOtherInRow->NextInRow; } pOtherInCol = Matrix->FirstInCol[I]; while(pOtherInCol != NULL) { if (pOtherInCol->Row >= Step && 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 && 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;}#else /* Not MODIFIED_MARKOWITZ *//* * QUICK SEARCH OF DIAGONAL FOR PIVOT WITH CONVENTIONAL 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. * * >>> Returned: * A pointer to the diagonal element chosen to be pivot. If no diagonal is * acceptable, a NULL is returned. * * >>> Arguments: * Matrix <input> (MatrixPtr) * Pointer to matrix. * 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. * MinMarkowitzProduct (long) * Smallest Markowitz product found of pivot candidates which are * acceptable. * pDiag (ElementPtr) * Pointer to current diagonal element. * pMarkowitzProduct (long *) * Pointer that points into MarkowitzProduct array. It is used to quickly * access successive Markowitz products. * 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;{long MinMarkowitzProduct, *pMarkowitzProduct; ElementPtr pDiag;int I;ElementPtr ChosenPivot, pOtherInRow, pOtherInCol;RealNumber Magnitude, LargestInCol, LargestOffDiagonal;RealNumber FindBiggestInColExclude(); /* Begin `QuicklySearchDiagonal'. */ ChosenPivot = NULL; 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)strchr on the diagonal is then * calculated by subtracting the pointer to the Markowitz product of
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -