#include <bits/stdc++.h>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
#include <fstream>
#include <map>
#include <set>
#include <ctime>
#include <memory>
#include <thread>
#include <chrono>
#include <random>
#include <regex>
#include <fstream>
#include <array>
#include <iostream>
#include <vector>
#include <iomanip>
#include <limits>
#include <algorithm>
#include <string>
class SimplexSolver {
private:
// Tableau representation (includes objective function, constraints and RHS)
std::vector<std::vector<double>> tableau;
// Keep track of basic variables for solution extraction
std::vector<int> basicVars;
// Number of decision variables (excluding slack/surplus variables)
int numVars;
// Number of constraints
int numConstraints;
// Total variables (including slack/surplus)
int totalVars;
// Flag to track if problem is solved
bool isSolved;
// Flag to track if problem is unbounded
bool isUnbounded;
// Flag to track if problem is infeasible
bool isInfeasible;
// Current iteration count
int iteration;
public:
// Constructor for the simplex solver
SimplexSolver() : isSolved(false), isUnbounded(false), isInfeasible(false), iteration(0) {}
// Method to set up the problem from user input
void setupProblem() {
std::cout << "======= Enter Linear Programming Problem =======" << std::endl;
// Get number of decision variables
std::cout << "Enter number of variables: ";
std::cin >> numVars;
// Get number of constraints
std::cout << "Enter number of constraints: ";
std::cin >> numConstraints;
// Calculate total variables (decision + slack)
totalVars = numVars + numConstraints;
// Initialize the tableau with zeros
// Rows = constraints + objective function row
// Columns = variables + slack variables + RHS
tableau.resize(numConstraints + 1, std::vector<double>(totalVars + 1, 0.0));
// Initialize basicVars to keep track of basic variables (initially slack variables)
basicVars.resize(numConstraints);
for (int i = 0; i < numConstraints; i++) {
basicVars[i] = numVars + i;
}
// Get objective function coefficients
std::cout << "\n======= Objective Function (Maximization) =======" << std::endl;
std::cout << "Enter coefficients of the objective function:" << std::endl;
for (int j = 0; j < numVars; j++) {
std::cout << "Coefficient of x" << j+1 << ": ";
std::cin >> tableau[numConstraints][j];
// Negate the coefficients for standard form (we'll use bottom row for reduced costs)
tableau[numConstraints][j] = -tableau[numConstraints][j];
}
// Get constraints
std::cout << "\n======= Constraints =======" << std::endl;
for (int i = 0; i < numConstraints; i++) {
std::cout << "Constraint " << i+1 << ":" << std::endl;
// Get coefficients for each variable in this constraint
for (int j = 0; j < numVars; j++) {
std::cout << "Coefficient of x" << j+1 << ": ";
std::cin >> tableau[i][j];
}
// Add slack variables (identity matrix part)
tableau[i][numVars + i] = 1.0;
// Get RHS (b value)
std::cout << "Right-hand side (b" << i+1 << "): ";
std::cin >> tableau[i][totalVars];
// Check for potential infeasibility at the beginning
if (tableau[i][totalVars] < 0) {
std::cout << "Warning: Negative RHS detected, the problem might be infeasible!" << std::endl;
}
}
std::cout << "\nInitial simplex tableau has been created!" << std::endl;
}
// Method to set up the problem from test case vectors
void setupFromTestCase(
const std::vector<double>& objectiveCoeffs,
const std::vector<std::vector<double>>& constraintCoeffs,
const std::vector<double>& rhsValues) {
numVars = objectiveCoeffs.size();
numConstraints = rhsValues.size();
totalVars = numVars + numConstraints;
// Initialize the tableau with zeros
tableau.resize(numConstraints + 1, std::vector<double>(totalVars + 1, 0.0));
// Initialize basicVars
basicVars.resize(numConstraints);
for (int i = 0; i < numConstraints; i++) {
basicVars[i] = numVars + i;
}
// Set objective function (negate for standard form)
for (int j = 0; j < numVars; j++) {
tableau[numConstraints][j] = -objectiveCoeffs[j];
}
// Set constraint coefficients and RHS values
for (int i = 0; i < numConstraints; i++) {
// Set coefficients for decision variables
for (int j = 0; j < numVars; j++) {
tableau[i][j] = constraintCoeffs[i][j];
}
// Set slack variable (1 for current constraint)
tableau[i][numVars + i] = 1.0;
// Set RHS
tableau[i][totalVars] = rhsValues[i];
}
std::cout << "Initial simplex tableau has been created from input data!" << std::endl;
}
// Method to print the current tableau
void displayTableau() const {
std::cout << "\n======= Simplex Tableau (Iteration " << iteration << ") =======" << std::endl;
// Print header row with variable names
std::cout << std::setw(5) << "Basic";
for (int j = 0; j < numVars; j++) {
std::cout << std::setw(10) << "x" + std::to_string(j+1);
}
for (int j = 0; j < numConstraints; j++) {
std::cout << std::setw(10) << "s" + std::to_string(j+1);
}
std::cout << std::setw(10) << "RHS" << std::endl;
// Print divider
std::cout << std::string(5 + 10 * (totalVars + 1), '-') << std::endl;
// Print constraint rows
for (int i = 0; i < numConstraints; i++) {
// Show which variable is basic in this row
if (basicVars[i] < numVars) {
std::cout << std::setw(5) << "x" + std::to_string(basicVars[i]+1);
} else {
std::cout << std::setw(5) << "s" + std::to_string(basicVars[i]-numVars+1);
}
// Print coefficients
for (int j = 0; j < totalVars + 1; j++) {
std::cout << std::setw(10) << std::fixed << std::setprecision(2) << tableau[i][j];
}
std::cout << std::endl;
}
// Print objective function row (Z row)
std::cout << std::setw(5) << "Z";
for (int j = 0; j < totalVars + 1; j++) {
std::cout << std::setw(10) << std::fixed << std::setprecision(2) << tableau[numConstraints][j];
}
std::cout << std::endl;
}
// Method to find the entering variable (most negative coefficient in bottom row)
int findEnteringVariable() const {
int enteringVar = -1;
double minCoeff = -1e-10; // Small epsilon to handle floating-point errors
// Check bottom row (objective function coefficients)
for (int j = 0; j < totalVars; j++) {
if (tableau[numConstraints][j] < minCoeff) {
minCoeff = tableau[numConstraints][j];
enteringVar = j;
}
}
return enteringVar;
}
// Method to find the leaving variable (smallest positive ratio)
int findLeavingVariable(int enteringVar) {
int leavingVar = -1;
double minRatio = std::numeric_limits<double>::max();
for (int i = 0; i < numConstraints; i++) {
// We only consider positive coefficients in the entering column
if (tableau[i][enteringVar] > 1e-10) {
double ratio = tableau[i][totalVars] / tableau[i][enteringVar];
if (ratio < minRatio && ratio >= 0) {
minRatio = ratio;
leavingVar = i;
}
}
}
// If no positive ratio is found, the problem is unbounded
if (leavingVar == -1) {
isUnbounded = true;
}
return leavingVar;
}
// Method to perform pivoting (Gaussian elimination)
void pivot(int enteringVar, int leavingRow) {
// Keep track of which variable becomes basic
basicVars[leavingRow] = enteringVar;
// Get the pivot element
double pivotElement = tableau[leavingRow][enteringVar];
// Normalize the pivot row (make pivot element 1)
for (int j = 0; j <= totalVars; j++) {
tableau[leavingRow][j] /= pivotElement;
}
// Update all other rows to make the pivot column zeros except at pivot position
for (int i = 0; i <= numConstraints; i++) {
if (i != leavingRow) {
double multiplier = tableau[i][enteringVar];
for (int j = 0; j <= totalVars; j++) {
tableau[i][j] -= multiplier * tableau[leavingRow][j];
}
}
}
}
// Method to solve the linear program using the Simplex method
void solve() {
while (true) {
iteration++;
displayTableau();
// Find entering variable (most negative coefficient in objective row)
int enteringVar = findEnteringVariable();
// If no negative coefficients, the solution is optimal
if (enteringVar == -1) {
isSolved = true;
break;
}
// Find the leaving variable
int leavingRow = findLeavingVariable(enteringVar);
// If there's no valid leaving variable, the problem is unbounded
if (isUnbounded) {
std::cout << "The problem is unbounded!" << std::endl;
break;
}
// Perform pivot operation
pivot(enteringVar, leavingRow);
}
// If the problem is solved, display the result
if (isSolved) {
std::cout << "Optimal solution found!" << std::endl;
displaySolution();
}
}
// Method to extract and display the final solution
void displaySolution() const {
std::cout << "\n======= Solution =======" << std::endl;
for (int i = 0; i < numVars; i++) {
double value = 0;
// Check if variable is basic
for (int j = 0; j < numConstraints; j++) {
if (basicVars[j] == i) {
value = tableau[j][totalVars];
break;
}
}
std::cout << "x" << i+1 << " = " << value << std::endl;
}
// Display objective function value (Z value)
double objValue = tableau[numConstraints][totalVars];
std::cout << "Objective value (Z) = " << -objValue << std::endl;
}
};
int main() {
SimplexSolver solver;
// Uncomment to manually enter problem data
// solver.setupProblem();
// Set up from a test case
solver.setupFromTestCase(
{5, 4}, // Objective function coefficients (Maximize Z = 3x1 + 2x2)
{{6, 4}, {1, 2},{-1,1},{0,1}}, // Constraint coefficients
{24,6,1,2} // RHS values (5 for constraint 1, 12 for constraint 2)
);
// Solve the problem
solver.solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/