/// <summary> /// If there was a first phase and the optimum of the objective function was 0 the model should be transformed to such a dictionary form on which the second phase can be executed. /// This function does the necessary changes on the model. /// </summary> /// <param name="model">The LP model wanted to be transformed to be eligible to the execution of the second phase.</param> /// <returns>The transformed LP model.</returns> private static LPModel ToSecondPhaseDictionaryForm(this LPModel model) { #region Throw out the 'var0 = 0' shaped constraint if any var constraintToRemove = model.Constraints.Where(constraint => constraint.LeftSide.Count == 1 && constraint.LeftSide.Any(term => term.Variable.Value.Index == 0) && (constraint.RightSide.Count == 1 || constraint.RightSide.Any(term => term.Constant && term.SignedCoefficient == 0)) || constraint.RightSide.Count == 0) .SingleOrDefault(); if (constraintToRemove != null) { model.Constraints.Remove(constraintToRemove); } #endregion #region If var0 is a basis variable it will be exchanged with a non-basis variable by a pivot step var constraintWithVar0Basis = model.Constraints.Where(constraint => constraint.LeftSide.Count == 1 && constraint.LeftSide.Any(term => term.Variable.Value.Index == 0)) .SingleOrDefault(); var var0 = new Variable { Name = model.AllVariables.First().Name, Index = 0 }; if (constraintWithVar0Basis != null) { // choosing the variable has a negative coefficient and the smallest index var newBasisVariable = constraintWithVar0Basis.RightSide .Where(term => term.Variable.Value.Index == constraintWithVar0Basis.RightSide .Where(t => t.Variable.HasValue /*&& t.SignedCoefficient < 0*/) .Min(t => t.Variable.Value.Index)) .Single().Variable.Value; model.MakePivotStep(newBasisVariable, var0, withoutObjectiveFunction: true); } #endregion #region Throw out the rest of the var0 occurences model.Constraints.ForAll(constraint => { var foundVar0 = constraint.RightSide.Where(term => term.Variable?.Equals(new Variable { Name = model.AllVariables.First().Name, Index = 0 }) ?? false).SingleOrDefault(); if (foundVar0 != null) { constraint.RightSide.Remove(foundVar0); } }); model.InterpretationRanges.Remove(model.InterpretationRanges.Single(range => range.LeftSide.Single().Variable?.Equals(var0) ?? false)); #endregion #region Set back the original objective function exhanging the basis variables with their equivaltent expressions from the dictionary (right sides) model.Objective = model.TmpObjective; model.Constraints.ForAll(constraint => { var basisVariable = constraint.LeftSide.Single(term => term.Variable.HasValue).Variable.Value; model.Objective.Function.ReplaceVarWithExpression(basisVariable, constraint.RightSide); }); #endregion return(model); }
/// <summary> /// Runs the simplex algoritm on the given LP model. /// </summary> /// <param name="model">The LP model on which the simplex algoritm will be executed.</param> /// <returns></returns> /// <exception cref="SimplexAlgorithmExectionException"></exception> public static LPModel RunSimplex(this LPModel model) { while (!model.AllObjectiveFunctionVariableHasNegativeCoefficient()) { #region Choosing new basis variable by Bland - let1s name its index as k var kIndex = model.Objective.Function.RightSide.Where(term => term.Variable.HasValue && term.SignedCoefficient > 0).Min(term => term.Variable.Value.Index); var stepInVariable = model.Objective.Function.RightSide.Where(term => term.Variable.HasValue && term.Variable.Value.Index == kIndex).Single().Variable.Value; #endregion #region All k-indexed variable has positive coefficient in the constraints? YES - stop, no limit, NO - continue Func <Term, bool> hasKIndex = term => term.Variable?.Equals(stepInVariable) ?? false; IEnumerable <Term> termsWithKIndexedVariables = model.Constraints.Where(constraint => constraint.RightSide.Any(term => hasKIndex(term))) .Select(constraint => constraint.RightSide.Where(term => hasKIndex(term)).Single()); bool allKIndexedHasPositiveIndex = termsWithKIndexedVariables.All(term => term.SignedCoefficient > 0); if (allKIndexedHasPositiveIndex) { throw new SimplexAlgorithmExectionException(SimplexAlgorithmExectionErrorType.NotLimited); } #endregion #region Determining the variable which will leave the base by finding the smallest quotient Equation selectedConstraint = null; Rational?smallestQuotient = null; model.Constraints.Where(constraint => constraint.RightSide.Any(term => hasKIndex(term) && term.SignedCoefficient < 0)) .ForAll(constraint => { // This value must be non-negative - if not the dictionary were not valid var constraintsConstantValue = constraint.RightSide.Where(term => term.Constant).SingleOrDefault()?.SignedCoefficient ?? 0; var kIndexedVariablesCoefficient = constraint.RightSide.Where(term => hasKIndex(term)).Single().SignedCoefficient; // If this is the fist ratio, we will store it automatically (smallestQuotient doesn't have a value yet var smallestQuotientFound = !smallestQuotient.HasValue || ((constraintsConstantValue / kIndexedVariablesCoefficient.Abs()) < smallestQuotient); if (smallestQuotientFound) { selectedConstraint = constraint; smallestQuotient = constraintsConstantValue / kIndexedVariablesCoefficient.Abs(); } }); var stepOutVariable = selectedConstraint.LeftSide.Single().Variable.Value; #endregion #region Making a pivot step model.MakePivotStep(stepInVariable, stepOutVariable); #endregion } return(model); }
/// <summary> /// Runs the dual simplex algoritm on the given LP model. /// </summary> /// <param name="lpModel">The LP model on wich the dual simplex method will be executed.</param> /// <returns>The LP model</returns> public static LPModel DualSimplex(this LPModel model) { while (!model.AllBasisVariableHaveNonNegativeValuesInTheDictionary()) { #region Choosing variable will step out from the base - choosing the dictionary row having the most negative index - we will choose the lowest index anyway var stepOutVariable = model.Constraints.Where(dictionaryRow => (dictionaryRow.RightSide.SingleOrDefault(term => term.Constant)?.SignedCoefficient ?? 0) < 0) .Select(dictionaryRow => new { Variable = dictionaryRow.LeftSide.Single().Variable.Value, Value = dictionaryRow.RightSide.Single(term => term.Constant).SignedCoefficient }) .OrderBy(variableValuePair => variableValuePair.Value) .ThenBy(variableValuePair => variableValuePair.Variable.Index) .First().Variable; #endregion var rowWithStepOutVariable = model.Constraints.Single(row => row.LeftSide.Single().Variable.Value.Equals(stepOutVariable)); if (rowWithStepOutVariable.RightSide.Where(term => !term.Constant).All(term => term.SignedCoefficient < 0)) { throw new SimplexAlgorithmExectionException(SimplexAlgorithmExectionErrorType.NoSolution); } #region Choosing the variable will step in the basis - by finding the smallest quotient var termsWithPositiveCoefficient = rowWithStepOutVariable.RightSide.Where(term => term.SignedCoefficient > 0 && !term.Constant); var varsWithQuotient = new Dictionary <Variable, Rational>(); termsWithPositiveCoefficient.ForAll(term => { var functionTermsCoefficient = model.Objective.Function.RightSide.SingleOrDefault(functionTerm => !functionTerm.Constant && functionTerm.Variable.Value.Equals(term.Variable.Value))?.SignedCoefficient ?? 0; varsWithQuotient.Add(term.Variable.Value, functionTermsCoefficient / term.SignedCoefficient); }); var stepInVariable = varsWithQuotient.OrderBy(kv => kv.Value).ThenBy(kv => kv.Key.Index).First().Key; #endregion #region Making a pivot step model.MakePivotStep(stepInVariable, stepOutVariable); #endregion } return(model); }