public SimplexResult Solve(SimplexTuple tuple) { var multiplier = 1; if (tuple.Type == ObjectiveFunctionType.Min) multiplier *= -1; var standartTuple = (new SimplexInputBuilder()).ConvertToStandartForm(tuple); var bInternal = InitializeSimplex(tuple); iteration = 0; var columns = Enumerable.Range(0, tuple.ObjFuncCoeffs.Count).ToArray(); var AB = standartTuple.EqualityCoeffs.Extract(bInternal.InequalityIndexes, columns); var bB = standartTuple.FreeTerms.Extract(bInternal.InequalityIndexes); var vector = SolveInternal(standartTuple.EqualityCoeffs, standartTuple.FreeTerms, standartTuple.ObjFuncCoeffs, bInternal, AB, bB); //Multiply result to -1 if we have min function at start var optimalValue = multiplier*(standartTuple.ObjFuncCoeffs.ToRowMatrix()*vector)[0]; return new SimplexResult {OptimalValue = optimalValue, OptimalVector = vector, Iteration = iteration}; }
internal StartingBasis InitializeSimplex(SimplexTuple tuple) { var negativeCount = tuple.FreeTerms.Count(x => x < 0); int varCount = tuple.ObjFuncCoeffs.Count; var startingEq = new List<int>(varCount); for (int i = 0; i < tuple.EqualityCoeffs.RowCount; i++) { var row = tuple.EqualityCoeffs.Row(i); if (row.Count(x => x.FloatEquals(-1)) == 1 && row.Count(x => x.FloatEquals(0)) == (varCount - 1) && startingEq.Count < varCount) startingEq.Add(i); } //If min index > 0 -> all free terms are positive. //This means that basis just zero variables and indexes of that inequalities if (negativeCount == 0) { return new StartingBasis { InequalityIndexes = startingEq.ToArray(), FeasibleBasis = new double[varCount] }; } //Create auxilary problem var auxObjFunc = new List<double>(varCount + negativeCount); auxObjFunc.AddRange(tuple.ObjFuncCoeffs.Select(ofc => 0).Select(dummy => (double) dummy)); var auxA = tuple.EqualityCoeffs.Clone(); var auxb = tuple.FreeTerms.Clone(); int rowCount = tuple.EqualityCoeffs.RowCount; //for each negative index we should go with added slack variable //TODO: work with Dense/Sparse vectors for (int i = 0; i < tuple.EqualityCoeffs.RowCount; i++) { if (tuple.FreeTerms[i] >= 0) continue; //add a new slack variable to obj function with coeff -1 auxObjFunc.Add(-1); //add new column for that variable var zeroVector = new DenseVector(rowCount); zeroVector[i] = -1; auxA = auxA.InsertColumn(varCount++, zeroVector); //add new row for this variable var nonNegativeRow = new DenseVector(varCount); nonNegativeRow[varCount - 1] = -1; auxA = auxA.InsertRow(rowCount, nonNegativeRow); var zeroFreeTerm = new DenseVector(new[] {0.0}); auxb = auxb.ToColumnMatrix().InsertRow(rowCount, zeroFreeTerm).Column(0); rowCount++; //add top constraint to this variable var freeTermRow = new DenseVector(varCount); freeTermRow[varCount - 1] = 1; auxA = auxA.InsertRow(rowCount, freeTermRow); var newFreeTerm = new DenseVector(new[] {-tuple.FreeTerms[i]}); auxb = auxb.ToColumnMatrix().InsertRow(rowCount, newFreeTerm).Column(0); startingEq.Add(rowCount); rowCount++; } var auxBasis = new StartingBasis { InequalityIndexes = startingEq.ToArray(), FeasibleBasis = new double[varCount] }; iteration = 0; var columns = Enumerable.Range(0, varCount).ToArray(); //TODO: work with Dense/Sparse vectors var auxAb = ((DenseMatrix) auxA).Extract(startingEq.ToArray(), columns); var auxbB = ((DenseVector) auxb).Extract(startingEq.ToArray()); Vector vector = SolveInternal((DenseMatrix) auxA, (DenseVector) auxb, new DenseVector(auxObjFunc.ToArray()), auxBasis, auxAb, auxbB); for (int k = tuple.ObjFuncCoeffs.Count; k < varCount; k++) if (!vector[k].FloatEquals(0)) throw new SimplexException("Problem is unsolvable"); var basis = vector.Take(tuple.ObjFuncCoeffs.Count).ToArray(); var indexes = auxBasis.InequalityIndexes.Where(x => x < tuple.EqualityCoeffs.RowCount).Take(tuple.ObjFuncCoeffs.Count).ToArray(); return new StartingBasis { InequalityIndexes = indexes, FeasibleBasis = basis }; }
public SimplexTuple ConvertToStandartForm(SimplexTuple tuple) { if (tuple.Type == ObjectiveFunctionType.Min) { tuple.ObjFuncCoeffs *= -1; tuple.ObjFuncFreeTerm *= -1; tuple.Type = ObjectiveFunctionType.Max; } int length = tuple.EquationTypes.Count; for (int i = 0; i < length; i++) { var equation = tuple.EquationTypes[i]; if (equation == EquationType.MoreOrEqual) { tuple.EqualityCoeffs.SetRow(i, -1*tuple.EqualityCoeffs.Row(i)); tuple.FreeTerms[i] *= -1; tuple.EquationTypes[i] = EquationType.LessOrEqual; } if (equation == EquationType.Equal) { tuple.EquationTypes[i] = EquationType.LessOrEqual; var additionalRow = tuple.EqualityCoeffs.Row(i).Clone(); tuple.EqualityCoeffs = (DenseMatrix) tuple.EqualityCoeffs.InsertRow(i + 1, additionalRow); tuple.EquationTypes.Insert(i + 1, EquationType.MoreOrEqual); var val = tuple.FreeTerms[i]; var freeTerms = tuple.FreeTerms.ToList(); freeTerms.Insert(i + 1, val); tuple.FreeTerms = new DenseVector(freeTerms.ToArray()); length++; } } return tuple; }