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 }; }
internal Vector SolveInternal(Matrix A, Vector b, Vector c, StartingBasis B, Matrix AB, Vector bB) { //Init simplex var m = A.RowCount; var ABi = AB.Inverse(); //X is a starting vector var x = AB.LU().Solve(bB); while (true) { iteration++; //Compute lambda (cT*AB.inv())T var lambda = (c.ToRowMatrix()*ABi).Transpose().ToRowWiseArray(); //check for optimality if (lambda.All(l => l >= 0)) return (Vector) x; //Find leaving index r (first index where component < 0) var r = lambda.Select((i, index) => new {i, index}) .Where((i, index) => i.i < 0) .First().index; //compute direction to move int - take r-th column var d = ABi.Column(r)*(-1); //Determine the set K (all indexes of positive values of lambda) //all k that a(k).T*d>0, 1 <= i <=m var K = new List<int>(); for (int k = 0; k < m; k++) { var val = A.Row(k)*d; if (val > 0 && !val.FloatEquals(0)) K.Add(k); } if (K.Count == 0) throw new SimplexException("Problem is unbounded") {Iteration = iteration}; //Find entering index e int e = 0; var v = double.MaxValue; foreach (var k in K) { var w = (b[k] - A.Row(k)*x)/(A.Row(k)*d); if (!(w < v)) continue; v = w; e = k; } //Update basis B.InequalityIndexes[r] = e; AB.SetRow(r, A.Row(e)); bB[r] = b[e]; //Trick - lets update inverse AB in a smart way - sinse there is only one new inequality we only need to //compute new inversed row (should drop complexity of whole algo to n*n) var f = AB.Row(r)*ABi; var g = -f; g[r] = 1; g /= f[r]; g[r] -= 1; ABi = ABi.Add(ABi.Column(r).ToColumnMatrix()*g.ToRowMatrix()); //Compute new x x = x + v*d; } }