Ejemplo n.º 1
0
 /// <summary>
 /// ctor, denominator will be set to one
 /// </summary>
 /// <param name="numerator"></param>
 public Rational(T numerator) : this(numerator, Policy.One())
 {
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Create the tableau by itself.
        /// </summary>
        /// <param name="maximize">if true, goal is to maximize the objective function</param>
        /// <returns>created tableau</returns>
        protected Matrix <T, TPolicy> CreateTableau(bool maximize)
        {
            // create a matrix of the correct size
            int width = numDecisionVariables + numSlackVariables +
                        numArtificialVariables + NumObjectiveFunctions + 1; // + 1 is for RHS
            int height = constraints.Count + NumObjectiveFunctions;
            var matrix = new Matrix <T, TPolicy>(width, height);

            var minusOne = Policy.Sub(Policy.Zero(), Policy.One());

            // initialize the objective function rows
            if (NumObjectiveFunctions == 2)
            {
                matrix[0, 0] = minusOne;
            }

            int zIndex = (NumObjectiveFunctions == 1) ? 0 : 1;

            matrix[zIndex, zIndex] = maximize ? Policy.One() : minusOne;

            Vector <T, TPolicy> objectiveCoefficients = maximize ? f.Coefficients * minusOne : f.Coefficients;
            var rowData = matrix.GetRow(zIndex);

            CopyArray(objectiveCoefficients.Data, rowData);
            matrix.SetRow(zIndex, rowData);
            matrix[width - 1, zIndex] = maximize ? f.ConstantTerm : Policy.Mul(minusOne, f.ConstantTerm);

            if (!restrictToNonNegative)
            {
                matrix[SlackVariableOffset - 1, zIndex] = InvertedCoefficientSum(objectiveCoefficients);
            }

            // initialize the constraint rows
            int slackVar      = 0;
            int artificialVar = 0;

            for (int i = 0; i < constraints.Count; i++)
            {
                var constraint = constraints[i];
                int row        = NumObjectiveFunctions + i;

                rowData = matrix.GetRow(row);
                // decision variable coefficients
                CopyArray(constraint.Coefficients.Data, rowData);
                matrix.SetRow(row, rowData);
                // x-
                if (!restrictToNonNegative)
                {
                    matrix[SlackVariableOffset - 1, row] =
                        InvertedCoefficientSum(constraint.Coefficients);
                }

                // RHS
                matrix[width - 1, row] = constraint.Value;

                // slack variables
                if (constraint.Relationship == Relationship.LEQ)
                {
                    matrix[SlackVariableOffset + slackVar++, row] = Policy.One();  // slack
                }
                else if (constraint.Relationship == Relationship.GEQ)
                {
                    matrix[SlackVariableOffset + slackVar++, row] = minusOne; // excess
                }

                // artificial variables
                if ((constraint.Relationship == Relationship.EQ) ||
                    (constraint.Relationship == Relationship.GEQ))
                {
                    matrix[ArtificialVariableOffset + artificialVar, 0]     = Policy.One();
                    matrix[ArtificialVariableOffset + artificialVar++, row] = Policy.One();
                    matrix.SetRowVector(0, matrix.GetRowVector(0) - matrix.GetRowVector(row));
                }
            }

            return(matrix);
        }
Ejemplo n.º 3
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]);
        }