Lets gooooo

This commit is contained in:
Zastian Pretorius
2022-08-02 12:42:49 +01:00
parent 782f31810c
commit eb9f7c6c67
88 changed files with 3246 additions and 2066 deletions

View File

@@ -0,0 +1,15 @@
using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BusinessLogic.Algorithms
{
public abstract class Algorithm
{
public abstract void PutModelInCanonicalForm(Model model);
public abstract void Solve(Model model);
}
}

View File

@@ -0,0 +1,293 @@
using Common;
using Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BusinessLogic.Algorithms
{
public class BranchAndBoundSimplex : Algorithm
{
private Model model;
public BinaryTree Results { get; set; } = new BinaryTree();
private DualSimplex dualSimplex = new DualSimplex();
private List<List<List<double>>> candidateSolutions = new List<List<List<double>>>();
public override void PutModelInCanonicalForm(Model model)
{
dualSimplex.PutModelInCanonicalForm(model);
Results.Add(model.Result);
}
public override void Solve(Model model)
{
this.model = model;
int level = 1;
while (level <= Results.GetHeight(Results.Root))
{
SolveCurrentLevel(Results.Root, level);
level++;
}
}
private void SolveCurrentLevel(BinaryTreeNode root, int level)
{
if (root == null)
return;
if (level == 1)
{
try
{
Solve(root);
Branch(root);
}
catch (InfeasibleException)
{
return;
}
}
else if (level > 1)
{
SolveCurrentLevel(root.LeftNode, level - 1);
SolveCurrentLevel(root.RightNode, level - 1);
}
}
public List<List<double>> GetBestCandidate()
{
double bestRHS = candidateSolutions[0][0][candidateSolutions[0][0].Count - 1];
List<List<double>> bestSolution = candidateSolutions[0];
for (int i = 1; i < candidateSolutions.Count; i++)
{
if (model.ProblemType == ProblemType.Maximization)
{
if (candidateSolutions[i][0][candidateSolutions[i][0].Count - 1] > bestRHS)
{
bestRHS = candidateSolutions[i][0][candidateSolutions[i][0].Count - 1];
bestSolution = candidateSolutions[i];
}
}
else
{
if (candidateSolutions[i][0][candidateSolutions[i][0].Count - 1] < bestRHS)
{
bestRHS = candidateSolutions[i][0][candidateSolutions[i][0].Count - 1];
bestSolution = candidateSolutions[i];
}
}
}
return bestSolution;
}
private void Solve(BinaryTreeNode root)
{
var model = new Model() { ProblemType = this.model.ProblemType, Result = root.Data };
dualSimplex.Solve(model);
}
private void Branch(BinaryTreeNode root)
{
if (CanBranch(root).Count == 0)
{
candidateSolutions.Add(root.Data[root.Data.Count - 1]);
}
else
{
// Get the variable we need to branch on
int branchVariableIndex = GetBranchVariable(root.Data[root.Data.Count - 1], CanBranch(root));
// Add the new constraints to the old table and add that resulting table to the binary tree
AddSubProblems(root, branchVariableIndex);
}
}
private void AddSubProblems(BinaryTreeNode root, int branchVariableIndex)
{
var table = root.Data[root.Data.Count - 1];
double rhs = GetRhsOfVariable(branchVariableIndex, table);
int constraintOneRhs;
int constraintTwoRhs;
constraintOneRhs = (int)Math.Truncate(rhs);
constraintTwoRhs = constraintOneRhs + 1;
var subProblemOneTable = ListCloner.CloneList(table);
var subProblemTwoTable = ListCloner.CloneList(table);
subProblemOneTable.Add(new List<double>());
subProblemTwoTable.Add(new List<double>());
for (int i = 0; i < subProblemOneTable[0].Count - 1; i++)
{
if (i == branchVariableIndex)
{
subProblemOneTable[subProblemOneTable.Count - 1].Add(1);
subProblemTwoTable[subProblemTwoTable.Count - 1].Add(-1);
}
else
{
subProblemOneTable[subProblemOneTable.Count - 1].Add(0);
subProblemTwoTable[subProblemTwoTable.Count - 1].Add(0);
}
}
subProblemOneTable[subProblemOneTable.Count - 1].Add(constraintOneRhs);
subProblemTwoTable[subProblemTwoTable.Count - 1].Add(constraintTwoRhs * -1);
for (int i = 0; i < subProblemOneTable.Count; i++)
{
var tempOne = subProblemOneTable[i][subProblemOneTable[i].Count - 1];
var tempTwo = subProblemTwoTable[i][subProblemTwoTable[i].Count - 1];
if (i == subProblemOneTable.Count - 1)
{
subProblemOneTable[i][subProblemOneTable[i].Count - 1] = 1;
subProblemTwoTable[i][subProblemTwoTable[i].Count - 1] = 1;
}
else
{
subProblemOneTable[i][subProblemOneTable[i].Count - 1] = 0;
subProblemTwoTable[i][subProblemTwoTable[i].Count - 1] = 0;
}
subProblemOneTable[i].Add(tempOne);
subProblemTwoTable[i].Add(tempTwo);
}
int subProblemBasicRow = GetBasicRow(table, branchVariableIndex);
for (int i = 0; i < subProblemOneTable[subProblemBasicRow].Count; i++)
{
subProblemOneTable[subProblemOneTable.Count - 1][i] -= subProblemOneTable[subProblemBasicRow][i];
subProblemTwoTable[subProblemTwoTable.Count - 1][i] += subProblemTwoTable[subProblemBasicRow][i];
}
Results.Add(new List<List<List<double>>>() { subProblemOneTable }, root.Data);
Results.Add(new List<List<List<double>>>() { subProblemTwoTable }, root.Data);
}
private int GetBasicRow(List<List<double>> table, int branchVariableIndex)
{
int basicRow = -1;
for (int i = 1; i < table.Count; i++)
{
if (table[i][branchVariableIndex] == 1)
{
basicRow = i;
break;
}
}
return basicRow;
}
private int GetBranchVariable(List<List<double>> table, List<int> intBinVarIndexes)
{
if (intBinVarIndexes.Count == 1)
return intBinVarIndexes[0];
int branchVariableIndex = -1;
decimal smallestFractionalPart = 1;
foreach (var intBinVar in intBinVarIndexes)
{
var rhs = (Decimal)GetRhsOfVariable(intBinVar, table);
decimal fractionalPart = rhs - Math.Truncate(rhs);
if (Math.Abs(0.5m - fractionalPart) < smallestFractionalPart)
{
smallestFractionalPart = Math.Abs(0.5m - fractionalPart);
branchVariableIndex = intBinVar;
}
}
return branchVariableIndex;
}
private List<int> CanBranch(BinaryTreeNode root)
{
var intBinVarIndexes = new List<int>();
var indexesToDiscard = new List<int>();
for (int i = 0; i < model.SignRestrictions.Count; i++)
{
if (model.SignRestrictions[i] == SignRestriction.Integer || model.SignRestrictions[i] == SignRestriction.Binary)
{
intBinVarIndexes.Add(i);
}
}
var table = root.Data[root.Data.Count - 1];
foreach (var intBinVar in intBinVarIndexes)
{
if (!IsVariableBasic(intBinVar, table))
{
indexesToDiscard.Add(intBinVar);
}
else
{
double rhs = GetRhsOfVariable(intBinVar, table);
if (rhs - Math.Truncate(rhs) < 0.00001)
{
indexesToDiscard.Add(intBinVar);
}
}
}
intBinVarIndexes.RemoveAll(v => indexesToDiscard.Contains(v) == true);
return intBinVarIndexes;
}
private double GetRhsOfVariable(int intBinVar, List<List<double>> table)
{
if (!IsVariableBasic(intBinVar, table))
return 0;
double rhs = 0;
for (int i = 1; i < table.Count; i++)
{
if (table[i][intBinVar] == 1)
{
rhs = table[i][table[i].Count - 1];
break;
}
}
return rhs;
}
private bool IsVariableBasic(int intBinVar, List<List<double>> table)
{
bool isBasic = true;
for (int i = 0; i < table.Count; i++)
{
int numberOfOnes = 0;
if (table[i][intBinVar] == 1)
numberOfOnes++;
if ((table[i][intBinVar] != 0 && table[i][intBinVar] != 1) || numberOfOnes > 1)
{
isBasic = false;
break;
}
}
return isBasic;
}
}
}

View File

@@ -0,0 +1,203 @@
using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BusinessLogic.Algorithms
{
public class CuttingPlane : Algorithm
{
private DualSimplex dualSimplex = new DualSimplex();
public override void PutModelInCanonicalForm(Model model)
{
dualSimplex.PutModelInCanonicalForm(model);
dualSimplex.Solve(model);
}
public override void Solve(Model model)
{
while (CanCut(model).Count > 0)
{
Cut(model);
dualSimplex.Solve(model);
}
}
private void Cut(Model model)
{
var table = model.Result[model.Result.Count - 1];
int cutVariableIndex = GetCutVariable(table, CanCut(model));
int basicRow = GetBasicRow(table, cutVariableIndex);
List<double> cutConstraint = GetCutConstraint(table, basicRow);
var newTable = ListCloner.CloneList(table);
newTable.Add(cutConstraint);
for (int i = 0; i < newTable.Count; i++)
{
if (i == newTable.Count - 1)
{
newTable[i].Insert(newTable[i].Count - 1, 1);
}
else
{
newTable[i].Insert(newTable[i].Count - 1, 0);
}
}
model.Result.Add(newTable);
}
private List<double> GetCutConstraint(List<List<double>> table, int basicRow)
{
List<double> cutConstraint = new List<double>();
for (int i = 0; i < table[basicRow].Count; i++)
{
if (table[basicRow][i] == Math.Truncate(table[basicRow][i]))
{
cutConstraint.Add(0);
}
else
{
double fractionalPart = Math.Abs(Math.Floor(table[basicRow][i]) - table[basicRow][i]);
cutConstraint.Add(-1 * fractionalPart);
}
}
return cutConstraint;
}
private List<int> CanCut(Model model)
{
List<int> intBinVarIndexes = new List<int>();
List<int> indexesToDiscard = new List<int>();
var lastTable = model.Result[model.Result.Count - 1];
for (int i = 0; i < model.SignRestrictions.Count; i++)
{
if (model.SignRestrictions[i] == SignRestriction.Integer || model.SignRestrictions[i] == SignRestriction.Binary)
{
intBinVarIndexes.Add(i);
}
}
foreach (var intBinVar in intBinVarIndexes)
{
if (!IsVariableBasic(intBinVar, lastTable))
{
indexesToDiscard.Add(intBinVar);
}
else
{
double rhs = GetRhsOfVariable(intBinVar, lastTable);
if (rhs - Math.Truncate(rhs) < 0.00001)
{
indexesToDiscard.Add(intBinVar);
}
}
}
intBinVarIndexes.RemoveAll(v => indexesToDiscard.Contains(v) == true);
return intBinVarIndexes;
}
private double GetRhsOfVariable(int intBinVar, List<List<double>> table)
{
if (!IsVariableBasic(intBinVar, table))
return 0;
double rhs = 0;
for (int i = 1; i < table.Count; i++)
{
if (table[i][intBinVar] == 1)
{
rhs = table[i][table[i].Count - 1];
break;
}
}
return rhs;
}
private bool IsVariableBasic(int intBinVar, List<List<double>> table)
{
bool isBasic = true;
for (int i = 0; i < table.Count; i++)
{
int numberOfOnes = 0;
if (table[i][intBinVar] == 1)
numberOfOnes++;
if ((table[i][intBinVar] != 0 && table[i][intBinVar] != 1) || numberOfOnes > 1)
{
isBasic = false;
break;
}
}
return isBasic;
}
private int GetCutVariable(List<List<double>> table, List<int> intBinVarIndexes)
{
if (intBinVarIndexes.Count == 1)
return intBinVarIndexes[0];
int branchVariableIndex = -1;
decimal smallestFractionalPart = 1;
foreach (var intBinVar in intBinVarIndexes)
{
var rhs = (Decimal)GetRhsOfVariable(intBinVar, table);
decimal fractionalPart = rhs - Math.Truncate(rhs);
if (Math.Abs(0.5m - fractionalPart) < smallestFractionalPart)
{
smallestFractionalPart = Math.Abs(0.5m - fractionalPart);
branchVariableIndex = intBinVar;
}
}
return branchVariableIndex;
}
private int GetBasicRow(List<List<double>> table, int variableIndex)
{
int basicRow = -1;
for (int i = 1; i < table.Count; i++)
{
if (table[i][variableIndex] == 1)
{
basicRow = i;
break;
}
}
return basicRow;
}
}
}

View File

@@ -0,0 +1,223 @@
using Common;
using Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BusinessLogic.Algorithms
{
public class DualSimplex : Algorithm
{
public override void PutModelInCanonicalForm(Model model)
{
List<List<double>> tableZero = new List<List<double>>();
tableZero.Add(new List<double>());
foreach (var decVar in model.ObjectiveFunction.DecisionVariables)
{
tableZero[0].Add(decVar.Coefficient * -1);
}
for (int i = 0; i < model.Constraints.Count; i++)
{
tableZero[0].Add(0);
if (model.Constraints[i].InequalitySign == InequalitySign.EqualTo)
tableZero[0].Add(0);
}
tableZero[0].Add(0);
var equalsConstraints = model.Constraints.Where(c => c.InequalitySign == InequalitySign.EqualTo).ToList();
if (equalsConstraints?.Count() > 0)
{
for (int i = 0; i < equalsConstraints.Count(); i++)
{
model.Constraints[model.Constraints.FindIndex(c => c == equalsConstraints[i])].InequalitySign = InequalitySign.LessThanOrEqualTo;
var newConstraint = new Constraint();
newConstraint.InequalitySign = InequalitySign.GreaterThanOrEqualTo;
newConstraint.RightHandSide = equalsConstraints[i].RightHandSide;
foreach (var decVar in equalsConstraints[i].DecisionVariables)
{
newConstraint.DecisionVariables.Add(new DecisionVariable() { Coefficient = decVar.Coefficient });
}
model.Constraints.Add(newConstraint);
}
}
for (int i = 0; i < model.Constraints.Count; i++)
{
List<double> constraintValues = new List<double>();
foreach (var decVar in model.Constraints[i].DecisionVariables)
{
if (model.Constraints[i].InequalitySign == InequalitySign.LessThanOrEqualTo)
{
constraintValues.Add(decVar.Coefficient);
}
else
{
constraintValues.Add(decVar.Coefficient * -1);
}
}
for (int j = 0; j < model.Constraints.Count; j++)
{
if (j == i)
{
constraintValues.Add(1);
}
else
{
constraintValues.Add(0);
}
}
if (model.Constraints[i].InequalitySign == InequalitySign.LessThanOrEqualTo)
{
constraintValues.Add(model.Constraints[i].RightHandSide);
}
else
{
constraintValues.Add(model.Constraints[i].RightHandSide * -1);
}
tableZero.Add(constraintValues);
}
model.Result.Add(tableZero);
}
public override void Solve(Model model)
{
Iterate(model);
var primalSimplex = new PrimalSimplex();
primalSimplex.Solve(model);
}
private void Iterate(Model model)
{
if (!CanPivot(model))
return;
int pivotRow = GetPivotRow(model);
int pivotColumn = GetPivotColumn(model, pivotRow);
if (pivotColumn == -1)
throw new InfeasibleException("There is no suitable column to pivot on - the problem is infeasible");
Pivot(model, pivotRow, pivotColumn);
Iterate(model);
}
private bool CanPivot(Model model)
{
bool canPivot = false;
var table = model.Result[model.Result.Count - 1];
for (int i = 1; i < table.Count; i++)
{
if (table[i][table[i].Count - 1] < -0.000000000001)
{
canPivot = true;
break;
}
}
return canPivot;
}
private int GetPivotRow(Model model)
{
int pivotRow = -1;
var table = model.Result[model.Result.Count - 1];
double mostNegative = 0;
for (int i = 1; i < table.Count; i++)
{
if (table[i][table[i].Count - 1] < 0 && table[i][table[i].Count - 1] < mostNegative)
{
mostNegative = table[i][table[i].Count - 1];
pivotRow = i;
}
}
return pivotRow;
}
private int GetPivotColumn(Model model, int pivotRow)
{
int pivotColumn = -1;
var table = model.Result[model.Result.Count - 1];
double lowestRatio = double.MaxValue;
for (int i = 0; i < table[0].Count - 1; i++)
{
if (table[pivotRow][i] < 0)
{
double ratio = Math.Abs(table[0][i] / table[pivotRow][i]);
if (ratio < lowestRatio)
{
lowestRatio = ratio;
pivotColumn = i;
}
}
}
return pivotColumn;
}
private void Pivot(Model model, int pivotRow, int pivotColumn)
{
var previousTable = model.Result[model.Result.Count - 1];
var newTable = new List<List<double>>();
for (int i = 0; i < previousTable.Count; i++)
{
newTable.Add(new List<double>());
for (int j = 0; j < previousTable[i].Count; j++)
{
newTable[i].Add(previousTable[i][j]);
}
}
double factor = 1 / newTable[pivotRow][pivotColumn];
for (int i = 0; i < newTable[pivotRow].Count; i++)
{
newTable[pivotRow][i] *= factor;
}
double pivotColumnValue;
for (int i = 0; i < newTable.Count; i++)
{
pivotColumnValue = newTable[i][pivotColumn];
if (i != pivotRow && pivotColumnValue != 0)
{
for (int j = 0; j < newTable[i].Count; j++)
{
newTable[i][j] += (-1 * pivotColumnValue * newTable[pivotRow][j]);
}
}
}
model.Result.Add(newTable);
}
}
}

View File

@@ -0,0 +1,212 @@
using Common;
using Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BusinessLogic.Algorithms
{
public class PrimalSimplex : Algorithm
{
public override void PutModelInCanonicalForm(Model model)
{
List<List<double>> tableZero = new List<List<double>>();
tableZero.Add(new List<double>());
foreach (var decVar in model.ObjectiveFunction.DecisionVariables)
{
tableZero[0].Add(decVar.Coefficient * -1);
}
for (int i = 0; i <= model.Constraints.Count; i++)
{
tableZero[0].Add(0);
}
for (int i = 0; i < model.Constraints.Count; i++)
{
List<double> constraintValues = new List<double>();
foreach (var decVar in model.Constraints[i].DecisionVariables)
{
constraintValues.Add(decVar.Coefficient);
}
for (int j = 0; j < model.Constraints.Count; j++)
{
if (j == i)
{
constraintValues.Add(1);
}
else
{
constraintValues.Add(0);
}
}
constraintValues.Add(model.Constraints[i].RightHandSide);
tableZero.Add(constraintValues);
}
model.Result.Add(tableZero);
}
public override void Solve(Model model)
{
Iterate(model);
}
private bool IsOptimal(Model model)
{
bool isOptimal = true;
var table = model.Result[model.Result.Count - 1];
if (model.ProblemType == ProblemType.Maximization)
{
for (int i = 0; i < table[0].Count - 1; i++)
{
if (table[0][i] < 0)
{
isOptimal = false;
break;
}
}
}
else
{
for (int i = 0; i < table[0].Count - 1; i++)
{
if (table[0][i] > 0)
{
isOptimal = false;
break;
}
}
}
return isOptimal;
}
private void Iterate(Model model)
{
if (IsOptimal(model))
return;
int pivotColumn = GetPivotColumn(model);
// Then get the pivot row
int pivotRow = GetPivotRow(model, pivotColumn);
if (pivotRow == -1)
throw new InfeasibleException("There is no suitable row to pivot on - the problem is infeasible");
Pivot(model, pivotRow, pivotColumn);
Iterate(model);
}
private void Pivot(Model model, int pivotRow, int pivotColumn)
{
var previousTable = model.Result[model.Result.Count - 1];
var newTable = new List<List<double>>();
for (int i = 0; i < previousTable.Count; i++)
{
newTable.Add(new List<double>());
for (int j = 0; j < previousTable[i].Count; j++)
{
newTable[i].Add(previousTable[i][j]);
}
}
double factor = 1 / newTable[pivotRow][pivotColumn];
for (int i = 0; i < newTable[pivotRow].Count; i++)
{
newTable[pivotRow][i] *= factor;
}
double pivotColumnValue;
for (int i = 0; i < newTable.Count; i++)
{
pivotColumnValue = newTable[i][pivotColumn];
if (i != pivotRow && pivotColumnValue != 0)
{
for (int j = 0; j < newTable[i].Count; j++)
{
newTable[i][j] += (-1 * pivotColumnValue * newTable[pivotRow][j]);
}
}
}
model.Result.Add(newTable);
}
private int GetPivotColumn(Model model)
{
int colIndex = -1;
var table = model.Result[model.Result.Count - 1];
if (model.ProblemType == ProblemType.Maximization)
{
double mostNegative = 0;
for (int i = 0; i < table[0].Count - 1; i++)
{
if (table[0][i] < 0 && table[0][i] < mostNegative)
{
mostNegative = table[0][i];
colIndex = i;
}
}
}
else
{
double mostPositive = 0;
for (int i = 0; i < table[0].Count - 1; i++)
{
if (table[0][i] > 0 && table[0][i] > mostPositive)
{
mostPositive = table[0][i];
colIndex = i;
}
}
}
return colIndex;
}
private int GetPivotRow(Model model, int pivotColumn)
{
int rowIndex = -1;
var table = model.Result[model.Result.Count - 1];
double lowestRatio = double.MaxValue;
for (int i = 1; i < table.Count; i++)
{
if (table[i][pivotColumn] > 0)
{
double ratio = table[i][table[i].Count - 1] / table[i][pivotColumn];
if (ratio < lowestRatio && ratio >= 0)
{
lowestRatio = ratio;
rowIndex = i;
}
}
}
return rowIndex;
}
}
}

View File

@@ -0,0 +1,346 @@
using Common;
using Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BusinessLogic.Algorithms
{
public class TwoPhaseSimplex : Algorithm
{
private int numberOfArtificialVars = 0;
public override void PutModelInCanonicalForm(Model model)
{
for (int i = 0; i < model.Constraints.Count; i++)
{
if (model.Constraints[i].RightHandSide < 0)
{
for (int j = 0; j < model.Constraints[i].DecisionVariables.Count; j++)
{
model.Constraints[i].DecisionVariables[j].Coefficient *= -1;
}
model.Constraints[i].RightHandSide *= -1;
if (model.Constraints[i].InequalitySign == InequalitySign.LessThanOrEqualTo)
{
model.Constraints[i].InequalitySign = InequalitySign.GreaterThanOrEqualTo;
}
else if (model.Constraints[i].InequalitySign == InequalitySign.GreaterThanOrEqualTo)
{
model.Constraints[i].InequalitySign = InequalitySign.LessThanOrEqualTo;
}
}
}
List<List<double>> tableZero = new List<List<double>>();
tableZero.Add(new List<double>());
foreach (var decVar in model.ObjectiveFunction.DecisionVariables)
{
tableZero[0].Add(decVar.Coefficient * -1);
}
foreach (var constraint in model.Constraints)
{
if (constraint.InequalitySign == InequalitySign.LessThanOrEqualTo ||
constraint.InequalitySign == InequalitySign.GreaterThanOrEqualTo)
{
tableZero[0].Add(0);
}
if (constraint.InequalitySign == InequalitySign.EqualTo ||
constraint.InequalitySign == InequalitySign.GreaterThanOrEqualTo)
{
tableZero[0].Add(0);
}
}
tableZero[0].Add(0);
for (int i = 0; i < model.Constraints.Count; i++)
{
List<double> constraintValues = new List<double>();
foreach (var decVar in model.Constraints[i].DecisionVariables)
{
constraintValues.Add(decVar.Coefficient);
}
for (int j = 0; j < model.Constraints.Count; j++)
{
if (model.Constraints[j].InequalitySign == InequalitySign.LessThanOrEqualTo)
{
if (j == i)
{
constraintValues.Add(1);
}
else
{
constraintValues.Add(0);
}
}
else if (model.Constraints[j].InequalitySign == InequalitySign.GreaterThanOrEqualTo)
{
if (j == i)
{
constraintValues.Add(-1);
}
else
{
constraintValues.Add(0);
}
}
}
constraintValues.Add(model.Constraints[i].RightHandSide);
for (int j = 0; j < model.Constraints.Count; j++)
{
if (model.Constraints[j].InequalitySign == InequalitySign.EqualTo ||
model.Constraints[j].InequalitySign == InequalitySign.GreaterThanOrEqualTo)
{
if (j == i)
{
constraintValues.Insert(constraintValues.Count - 1, 1);
}
else
{
constraintValues.Insert(constraintValues.Count - 1, 0);
}
}
}
tableZero.Add(constraintValues);
}
numberOfArtificialVars = model.Constraints.Where(c => c.InequalitySign ==
InequalitySign.EqualTo || c.InequalitySign == InequalitySign.GreaterThanOrEqualTo).Count();
List<double> wRow = new List<double>();
for (int i = 0; i < tableZero[0].Count; i++)
{
wRow.Add(0);
}
for (int i = 1; i < tableZero.Count; i++)
{
if (model.Constraints[i - 1].InequalitySign == InequalitySign.EqualTo ||
model.Constraints[i - 1].InequalitySign == InequalitySign.GreaterThanOrEqualTo)
{
for (int j = 0; j < (tableZero[i].Count - numberOfArtificialVars - 1); j++)
{
wRow[j] += tableZero[i][j];
}
wRow[wRow.Count - 1] += tableZero[i][tableZero[i].Count - 1];
}
}
tableZero.Insert(0, wRow);
model.Result.Add(tableZero);
}
public override void Solve(Model model)
{
Iterate(model);
var lastTable = model.Result[model.Result.Count - 1];
if (lastTable[0][lastTable[0].Count - 1] > 0)
{
throw new InfeasibleException("The problem is infeasible");
}
bool allArtificialsNonBasic = true;
for (int i = lastTable[0].Count - (numberOfArtificialVars + 1); i < lastTable[0].Count - 1; i++)
{
if (IsVariableBasic(i, lastTable))
{
allArtificialsNonBasic = false;
break;
}
}
if (allArtificialsNonBasic)
{
lastTable.RemoveAt(0);
for (int i = 0; i < lastTable.Count; i++)
{
for (int j = 0; j < numberOfArtificialVars; j++)
{
lastTable[i].RemoveAt(lastTable[i].Count - 2);
}
}
}
else
{
for (int i = 0; i < model.ObjectiveFunction.DecisionVariables.Count; i++)
{
if (lastTable[0][i] < 0)
{
for (int j = 0; j < lastTable.Count; j++)
{
lastTable[j].RemoveAt(i);
}
}
}
for (int i = lastTable[0].Count - (numberOfArtificialVars + 1); i < lastTable[0].Count - 1; i++)
{
if (!IsVariableBasic(i, lastTable))
{
for (int j = 0; j < lastTable.Count; j++)
{
lastTable[j].RemoveAt(i);
}
}
}
lastTable.RemoveAt(0);
}
var primalSimplex = new PrimalSimplex();
primalSimplex.Solve(model);
}
private bool IsOptimal(Model model)
{
bool isOptimal = true;
var table = model.Result[model.Result.Count - 1];
for (int i = 0; i < table[0].Count - 1; i++)
{
if (table[0][i] > 0)
{
isOptimal = false;
break;
}
}
return isOptimal;
}
private void Iterate(Model model)
{
if (IsOptimal(model))
return;
int pivotColumn = GetPivotColumn(model);
int pivotRow = GetPivotRow(model, pivotColumn);
if (pivotRow == -1)
throw new InfeasibleException("There is no suitable row to pivot on - the problem is infeasible");
Pivot(model, pivotRow, pivotColumn);
Iterate(model);
}
private void Pivot(Model model, int pivotRow, int pivotColumn)
{
var previousTable = model.Result[model.Result.Count - 1];
var newTable = new List<List<double>>();
for (int i = 0; i < previousTable.Count; i++)
{
newTable.Add(new List<double>());
for (int j = 0; j < previousTable[i].Count; j++)
{
newTable[i].Add(previousTable[i][j]);
}
}
double factor = 1 / newTable[pivotRow][pivotColumn];
for (int i = 0; i < newTable[pivotRow].Count; i++)
{
newTable[pivotRow][i] *= factor;
}
double pivotColumnValue;
for (int i = 0; i < newTable.Count; i++)
{
pivotColumnValue = newTable[i][pivotColumn];
if (i != pivotRow && pivotColumnValue != 0)
{
for (int j = 0; j < newTable[i].Count; j++)
{
newTable[i][j] += (-1 * pivotColumnValue * newTable[pivotRow][j]);
}
}
}
model.Result.Add(newTable);
}
private int GetPivotColumn(Model model)
{
int colIndex = -1;
var table = model.Result[model.Result.Count - 1];
double mostPositive = 0;
for (int i = 0; i < table[0].Count - 1; i++)
{
if (table[0][i] > 0 && table[0][i] > mostPositive)
{
mostPositive = table[0][i];
colIndex = i;
}
}
return colIndex;
}
private int GetPivotRow(Model model, int pivotColumn)
{
int rowIndex = -1;
var table = model.Result[model.Result.Count - 1];
double lowestRatio = double.MaxValue;
for (int i = 1; i < table.Count; i++)
{
if (table[i][pivotColumn] > 0)
{
double ratio = table[i][table[i].Count - 1] / table[i][pivotColumn];
if (ratio < lowestRatio && ratio >= 0)
{
lowestRatio = ratio;
rowIndex = i;
}
}
}
return rowIndex;
}
private bool IsVariableBasic(int index, List<List<double>> table)
{
bool isBasic = true;
for (int i = 0; i < table.Count; i++)
{
int numberOfOnes = 0;
if (table[i][index] == 1)
numberOfOnes++;
if ((table[i][index] != 0 && table[i][index] != 1) || numberOfOnes > 1)
{
isBasic = false;
break;
}
}
return isBasic;
}
}
}