예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        /// <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);
        }