public void DegeneracyTest() { #region Arrange var target = new Solver(); var lc1 = new LinearConstraint() { Coefficients = new double[3] { 1, 1, 0 }, Relationship = Relationship.LessThanOrEquals, Value = 1 }; var lc2 = new LinearConstraint() { Coefficients = new double[3] { 0, -1, 1 }, Relationship = Relationship.LessThanOrEquals, Value = 0 }; var constraints = new List<LinearConstraint>() { lc1, lc2 }; var goal = new Goal() { Coefficients = new double[3] { 1, 1, 1 }, ConstantTerm = 0 }; var model = new Model() { Constraints = constraints, Goal = goal, GoalKind = GoalKind.Maximize }; var expected = new Solution() { Decisions = new double[3] { 0, 1, 1 }, Quality = SolutionQuality.Optimal, AlternateSolutionsExist = false, OptimalValue = 2 }; #endregion //Act var actual = target.Solve(model); //Assert CollectionAssert.AreEqual(expected.Decisions, actual.Decisions); Assert.AreEqual(expected.Quality, actual.Quality); Assert.AreEqual(expected.AlternateSolutionsExist, actual.AlternateSolutionsExist); }
public void TwoPhaseClassTest() { #region Arrange var target = new Solver(); var lc1 = new LinearConstraint() { Coefficients = new double[2] { 1, 1 }, Relationship = Relationship.LessThanOrEquals, Value = 35 }; var lc2 = new LinearConstraint() { Coefficients = new double[2] { 1, 2 }, Relationship = Relationship.LessThanOrEquals, Value = 38 }; var lc3 = new LinearConstraint() { Coefficients = new double[2] { 2, 2 }, Relationship = Relationship.LessThanOrEquals, Value = 50 }; var constraints = new List<LinearConstraint>() { lc1, lc2, lc3 }; var goal = new Goal() { Coefficients = new double[2] { 350, 450 }, ConstantTerm = 0 }; var model = new Model() { Constraints = constraints, Goal = goal, GoalKind = GoalKind.Maximize }; var expected = new Solution() { Decisions = new double[2] { 12, 13 }, Quality = SolutionQuality.Optimal, AlternateSolutionsExist = false, OptimalValue = 10050 // 12*350 + 13*450 }; var actual = target.Solve(model); #endregion ////Act ////Assert CollectionAssert.AreEqual(expected.Decisions, actual.Decisions); Assert.AreEqual(expected.Quality, actual.Quality); Assert.AreEqual(expected.AlternateSolutionsExist, actual.AlternateSolutionsExist); }
public DenseMatrix createMatrix(Model model) { int numConstraints = model.Constraints.Count; int numDecisionVars = model.Goal.Coefficients.Length; int varCounter = numDecisionVars; // matrix(rows, columns) DenseMatrix coefficients = new DenseMatrix(numConstraints, numDecisionVars); DenseMatrix artificialVars = new DenseMatrix(numConstraints, 1); var constraintCounter = 0; this.rhsValues = new DenseVector(numConstraints); this.basics = new List<int>(); this.artificialRows = new List<int>(); foreach (var constraint in model.Constraints) { rhsValues[constraintCounter] = constraint.Value; // if the constraint RHS is negative, invert the coefficients and flip the inequality sign if (constraint.Value < 0) { for (int i = 0; i< model.Goal.Coefficients.Length; i++) { model.Goal.Coefficients[i] = model.Goal.Coefficients[i] * -1; } if (constraint.Relationship == Relationship.LessThanOrEquals) { constraint.Relationship = Relationship.GreaterThanOrEquals; } else if (constraint.Relationship == Relationship.GreaterThanOrEquals) { constraint.Relationship = Relationship.LessThanOrEquals; } // also flip the rhs value which we already put in the array for the simplex setup rhsValues[constraintCounter] = rhsValues[constraintCounter] * -1; } coefficients.SetRow(constraintCounter, 0, constraint.Coefficients.Length, new DenseVector(constraint.Coefficients)); // if it's a less than, add a slack column to the coefs matrix if (constraint.Relationship == Relationship.LessThanOrEquals) { DenseVector slack = DenseVector.Create(model.Constraints.Count, delegate(int s) { return 0; }); slack.At(constraintCounter, 1); coefficients = (DenseMatrix)coefficients.Append(slack.ToColumnMatrix()); this.basics.Add(varCounter); } else { // Need to add an artificial variable for >= and = constraints DenseVector surplus = DenseVector.Create(model.Constraints.Count, delegate(int s) { return 0; }); surplus.At(constraintCounter, -1); coefficients = (DenseMatrix)coefficients.Append(surplus.ToColumnMatrix()); DenseVector artificial = DenseVector.Create(model.Constraints.Count, delegate(int s) { return 0; }); artificial.At(constraintCounter, 1); artificialVars = (DenseMatrix)artificialVars.Append(artificial.ToColumnMatrix()); // Keeps track of the rows with artificial variable, for setting w artificialRows.Add(constraintCounter); } varCounter++; constraintCounter++; } // put the constraints and stuff into the matrix if (artificialVars.ColumnCount > 1) { artificialVars = (DenseMatrix)artificialVars.SubMatrix(0, artificialVars.RowCount, 1, artificialVars.ColumnCount - 1); for (int i = coefficients.ColumnCount; i < coefficients.ColumnCount + artificialVars.ColumnCount; i++) { this.basics.Add(i); } coefficients = (DenseMatrix)coefficients.Append(artificialVars); numArtificial = artificialVars.ColumnCount; } else { numArtificial = 0; } return coefficients; }
public void Simple2PhaseFromPaper() { #region Arrange var target = new Solver(); var lc1 = new LinearConstraint() { Coefficients = new double[2] { 1, 1 }, Relationship = Relationship.GreaterThanOrEquals, Value = 4 }; var lc2 = new LinearConstraint() { Coefficients = new double[2] { 1, -1 }, Relationship = Relationship.GreaterThanOrEquals, Value = 1 }; var lc3 = new LinearConstraint() { Coefficients = new double[2] { -1, 2 }, Relationship = Relationship.GreaterThanOrEquals, Value = -1 }; var constraints = new List<LinearConstraint>() { lc1, lc2, lc3 }; var goal = new Goal() { Coefficients = new double[2] { 1, 2 }, ConstantTerm = 0 }; var model = new Model() { Constraints = constraints, Goal = goal, GoalKind = GoalKind.Minimize }; var expected = new Solution() { Decisions = new double[2] { 3, 1 }, Quality = SolutionQuality.Optimal, AlternateSolutionsExist = false, OptimalValue = 5 }; #endregion //Act var actual = target.Solve(model); //Assert CollectionAssert.AreEqual(expected.Decisions, actual.Decisions); Assert.AreEqual(expected.Quality, actual.Quality); Assert.AreEqual(expected.AlternateSolutionsExist, actual.AlternateSolutionsExist); }
public Solution Solve(Model model) { DenseVector testVect = DenseVector.Create(10, delegate(int s) { return s; }); DenseMatrix coefficients = createMatrix(model); //gets the coefficients from the goal DenseVector objFunCoeffs = new DenseVector(model.Goal.Coefficients); //adds zeroes for the surplus/slack/artificial variables DenseVector objFunValues = DenseVector.Create((coefficients.ColumnCount), delegate(int s) { return 0; }); objFunValues.SetSubVector(0, objFunCoeffs.Count, objFunCoeffs); //flips the sign of everything if (model.GoalKind == GoalKind.Maximize) { objFunValues = DenseVector.Create((coefficients.ColumnCount), delegate(int s) { return -objFunValues[s]; }); } //here so I don't have to pass the model in :) numConstraints = model.Constraints.Count; //Maybe I could be smarter about where I put this (at the end of createMatrix?) //take care of artificial variable stuff if(numArtificial > 0) { //adds the z row to the coefficients matrix //adds the column first coefficients = (DenseMatrix)coefficients.Append(DenseVector.Create((coefficients.RowCount), delegate(int s) { return 0; }).ToColumnMatrix()); coefficients = (DenseMatrix)coefficients.InsertRow(coefficients.RowCount, DenseVector.Create(coefficients.ColumnCount, delegate(int s) { if (s == coefficients.ColumnCount - 1) return 1; else return -objFunValues[s]; })); //adds a 0 to match the z row rhsValues = DenseVector.Create(rhsValues.Count + 1, delegate(int s) { if (s == rhsValues.Count) { return model.Goal.ConstantTerm; } else { return rhsValues[s]; } }); //changes the objFunValues to be the w thingy objFunValues = DenseVector.Create(coefficients.ColumnCount, delegate(int s) { double sum = 0; //minus 1 because we also added a column for z if (s < coefficients.ColumnCount - numArtificial - 1) { //calculate each w row entry by foreach (int index in artificialRows) { sum += coefficients[index, s]; } return sum; } else { return 0; } }); //z is now a basic variable?? basics.Add(coefficients.ColumnCount - 1); printMat(coefficients); //solves it for that optimize(coefficients, objFunValues, true); basics.Remove(coefficients.ColumnCount - 1); //gets rid of the last value rhsValues = (DenseVector)rhsValues.SubVector(0, (rhsValues.Count - 1)); //chops off the z row and the artificial variables coefficients = (DenseMatrix)coefficients.SubMatrix(0, coefficients.RowCount - 1, 0, coefficients.ColumnCount - 1 - numArtificial); } printMat(coefficients); optimize(coefficients, objFunValues, false); /* * To find the solution: * The first columns in the mattress (that aren't * ssa variables) should be basic variables * Find what the final value is by finding their indices * in basics and then the value at that index in xprimes * should be what you're looking for I think * At least it's somewhere in xprimes */ double[] solution = new double[model.Goal.Coefficients.Length]; double op = model.Goal.ConstantTerm; for(int i = 0; i < solution.Length; i++) { solution[i] = xPrime[basics.IndexOf(i), 0]; op += solution[i] * model.Goal.Coefficients[i]; } Solution sol = new Solution() { Decisions = solution, OptimalValue = op, AlternateSolutionsExist = false, Quality = SolutionQuality.Optimal }; return sol; }