/// <inheritdoc /> protected override PointValuePair <T> DoOptimize() { // reset the tableau to indicate a non-feasible solution in case // we do not pass phase 1 successfully if (solutionCallback != null) { solutionCallback.Tableau = null; } var tableau = new SimplexTableau <T, TPolicy>(Function, Constraints, GoalType, IsRestrictedToNonNegative, epsilon, maxUlps); SolvePhase1(tableau); tableau.DropPhase1Objective(); // after phase 1, we are sure to have a feasible solution if (solutionCallback != null) { solutionCallback.Tableau = tableau; } while (!tableau.IsOptimal()) { DoIteration(tableau); } // check that the solution respects the nonNegative restriction in case // the epsilon/cutOff values are too large for the actual linear problem // (e.g. with very small constraint coefficients), the solver might actually // find a non-valid solution (with negative coefficients). PointValuePair <T> solution = tableau.GetSolution(); if (IsRestrictedToNonNegative) { T[] coeff = solution.Point; for (int i = 0; i < coeff.Length; i++) { if (Precision <T, TPolicy> .CompareTo(coeff[i], Policy.Zero(), epsilon) < 0) { throw new NoFeasibleSolutionException(); } } } return(solution); }
/// <summary> /// Solves Phase 1 of the Simplex method. /// </summary> /// <param name="tableau"></param> protected void SolvePhase1(SimplexTableau <T, TPolicy> tableau) { // make sure we're in Phase 1 if (tableau.NumArtificialVariables == 0) { return; } while (!tableau.IsOptimal()) { DoIteration(tableau); } // if W is not zero then we have no feasible solution if (!Precision <T, TPolicy> .Equals(tableau.GetEntry(0, tableau.RhsOffset), Policy.Zero(), epsilon)) { throw new NoFeasibleSolutionException(); } }