Ejemplo n.º 1
0
        /// <summary>
        /// Returns the row with the minimum ratio as given by the minimum ratio test (MRT).
        /// </summary>
        /// <param name="tableau"></param>
        /// <param name="col"></param>
        /// <returns></returns>
        private int?GetPivotRow(SimplexTableau <T, TPolicy> tableau, int col)
        {
            // create a list of all the rows that tie for the lowest score in the minimum ratio test
            List <int?> minRatioPositions   = new List <int?>();
            T           minRatio            = default(T);
            bool        minRationUnassigned = true;

            for (int i = tableau.NumObjectiveFunctions; i < tableau.Height; i++)
            {
                T rhs   = tableau.GetEntry(i, tableau.Width - 1);
                T entry = tableau.GetEntry(i, col);

                // only consider pivot elements larger than the cutOff threshold
                // selecting others may lead to degeneracy or numerical instabilities
                if (Precision <T, TPolicy> .CompareTo(entry, Policy.Zero(), cutOff) > 0)
                {
                    T ratio = Policy.Abs(Policy.Div(rhs, entry));
                    // check if the entry is strictly equal to the current min ratio
                    // do not use a ulp/epsilon check
                    int cmp;
                    if (minRationUnassigned)
                    {
                        cmp = -1;
                    }
                    else
                    {
                        cmp = Policy.Compare(ratio, minRatio);
                    }
                    if (cmp == 0)
                    {
                        minRatioPositions.Add(i);
                    }
                    else if (cmp < 0)
                    {
                        minRatio            = ratio;
                        minRationUnassigned = false;
                        minRatioPositions.Clear();
                        minRatioPositions.Add(i);
                    }
                }
            }

            if (minRatioPositions.Count == 0)
            {
                return(null);
            }
            else if (minRatioPositions.Count > 1)
            {
                // there's a degeneracy as indicated by a tie in the minimum ratio test

                // 1. check if there's an artificial variable that can be forced out of the basis
                if (tableau.NumArtificialVariables > 0)
                {
                    foreach (int?row in minRatioPositions)
                    {
                        for (int i = 0; i < tableau.NumArtificialVariables; i++)
                        {
                            int column = i + tableau.ArtificialVariableOffset;
                            T   entry  = tableau.GetEntry(row.Value, column);
                            if (Precision <T, TPolicy> .Equals(entry, Policy.One(), epsilon) && row.Equals(tableau.GetBasicRow(column)))
                            {
                                return(row);
                            }
                        }
                    }
                }

                // 2. apply Bland's rule to prevent cycling:
                //    take the row for which the corresponding basic variable has the smallest index
                //
                // see http://www.stanford.edu/class/msande310/blandrule.pdf
                // see http://en.wikipedia.org/wiki/Bland%27s_rule (not equivalent to the above paper)

                int?minRow   = null;
                int minIndex = tableau.Width;
                foreach (int?row in minRatioPositions)
                {
                    int basicVar = tableau.GetBasicVariable(row.Value);
                    if (basicVar < minIndex)
                    {
                        minIndex = basicVar;
                        minRow   = row;
                    }
                }
                return(minRow);
            }
            return(minRatioPositions[0]);
        }