/// <summary> /// Build a constraint involving two linear equations. /// </summary> /// <param name="lhsCoefficients">The coefficients of the linear expression on the left hand side of the constraint</param> /// <param name="lhsConstant">The constant term of the linear expression on the left hand side of the constraint</param> /// <param name="relationship">The type of (in)equality used in the constraint</param> /// <param name="rhsCoefficients">The coefficients of the linear expression on the right hand side of the constraint</param> /// <param name="rhsConstant">The constant term of the linear expression on the right hand side of the constraint</param> public LinearConstraint(T[] lhsCoefficients, T lhsConstant, Relationship relationship, T[] rhsCoefficients, T rhsConstant) { T[] sub = new T[lhsCoefficients.Length]; for (int i = 0; i < sub.Length; ++i) { sub[i] = Policy.Sub(lhsCoefficients[i], rhsCoefficients[i]); } Coefficients = new Vector <T, TPolicy>(sub, false); Relationship = relationship; Value = Policy.Sub(rhsConstant, lhsConstant); }
/// <summary> /// Subtract and normalize /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> public static Rational <T, TPolicy> operator -(Rational <T, TPolicy> a, Rational <T, TPolicy> b) { if (Policy.IsZero(a.Numerator)) { return(b); } if (Policy.IsZero(b.Numerator)) { return(a); } if (Policy.IsOne(a.Denominator) && Policy.IsOne(b.Denominator)) { return(new Rational <T, TPolicy>(Policy.Sub(a.Numerator, b.Numerator), a.Denominator)); } var d = Policy.Lcd(a.Denominator, b.Denominator); var an = Policy.Mul(a.Numerator, (Policy.Div(d, a.Denominator))); var bn = Policy.Mul(b.Numerator, (Policy.Div(d, b.Denominator))); return(new Rational <T, TPolicy>(Policy.Sub(an, bn), d).Normalize()); }
/// <summary> /// Returns the column with the most negative coefficient in the objective function row. /// </summary> /// <param name="tableau"></param> /// <returns></returns> private int?GetPivotColumn(SimplexTableau <T, TPolicy> tableau) { T minValue = Policy.Zero(); int?minPos = null; for (int i = tableau.NumObjectiveFunctions; i < tableau.Width - 1; i++) { T entry = tableau.GetEntry(0, i); // check if the entry is strictly smaller than the current minimum // do not use a ulp/epsilon check if (Policy.IsBelowZero(Policy.Sub(entry, minValue))) { minValue = entry; minPos = i; // Bland's rule: chose the entering column with the lowest index if (pivotSelection == PivotSelectionRule.BLAND && IsValidPivotColumn(tableau, i)) { break; } } } return(minPos); }
/// <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); }
/// <summary> /// True if |x - y| <= eps /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="eps"></param> /// <returns></returns> public static bool Equals(T x, T y, T eps) { return(Policy.IsBelowZero(Policy.Sub(Policy.Abs(Policy.Sub(y, x)), eps))); }