From 76aea53130118914a33e67fc666c0b580e2c830b Mon Sep 17 00:00:00 2001 From: MohdFuzailHaider Date: Thu, 10 Oct 2024 02:41:30 +0530 Subject: [PATCH 1/4] Add linear programming implementation using the simplex method --- my_script.py | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 my_script.py diff --git a/my_script.py b/my_script.py new file mode 100644 index 000000000000..e9f072a7afc9 --- /dev/null +++ b/my_script.py @@ -0,0 +1,120 @@ +import numpy as np + +class Tableau: + def __init__(self, tableau): + self.tableau = tableau + self.num_rows, self.num_cols = tableau.shape + + def pivot(self, row, col): + # Divide the pivot row by the pivot element + self.tableau[row] /= self.tableau[row, col] + + # Subtract multiples of the pivot row from all other rows + for i in range(self.num_rows): + if i != row: + self.tableau[i] -= self.tableau[i, col] * self.tableau[row] + + def find_pivot_column(self): + # The pivot column is the most negative value in the objective row (row 0) + obj_row = self.tableau[0, :-1] + pivot_col = np.argmin(obj_row) + if obj_row[pivot_col] >= 0: + return -1 # No negative value, we are done + return pivot_col + + def find_pivot_row(self, pivot_col): + # Calculate the ratios of the right-hand side to the pivot column entries + rhs = self.tableau[1:, -1] + col = self.tableau[1:, pivot_col] + ratios = [] + for i in range(len(rhs)): + if col[i] > 0: + ratios.append(rhs[i] / col[i]) + else: + ratios.append(np.inf) # Ignore non-positive entries + + pivot_row = np.argmin(ratios) + 1 # Add 1 because we ignored row 0 + if np.isinf(ratios[pivot_row - 1]): + return -1 # No valid pivot row (unbounded) + return pivot_row + + def run_simplex(self): + while True: + pivot_col = self.find_pivot_column() + if pivot_col == -1: + break # Optimal solution found + + pivot_row = self.find_pivot_row(pivot_col) + if pivot_row == -1: + raise ValueError("Linear program is unbounded.") + + self.pivot(pivot_row, pivot_col) + + return self.extract_solution() + + def extract_solution(self): + solution = np.zeros(self.num_cols - 1) + for i in range(1, self.num_rows): + col = self.tableau[i, :-1] + if np.count_nonzero(col) == 1: + solution[np.argmax(col)] = self.tableau[i, -1] + return solution, -self.tableau[0, -1] # Return solution and optimal value + +def construct_tableau(objective, constraints, rhs): + """ + Constructs the initial tableau for the simplex algorithm. + + Parameters: + - objective: List of coefficients of the objective function (maximize). + - constraints: List of lists representing coefficients of the constraints. + - rhs: List of right-hand-side values of constraints. + + Returns: + - tableau: A numpy array representing the initial simplex tableau. + """ + n_constraints = len(constraints) + n_vars = len(objective) + + # Creating the tableau matrix + tableau = np.zeros((n_constraints + 1, n_vars + n_constraints + 1)) + + # Fill the objective function (row 0, cols 0 to n_vars) + tableau[0, :n_vars] = -np.array(objective) # Maximization -> negate + + # Fill the constraints + for i in range(n_constraints): + tableau[i + 1, :n_vars] = constraints[i] + tableau[i + 1, n_vars + i] = 1 # Slack variable + tableau[i + 1, -1] = rhs[i] # RHS of the constraints + + return tableau + +def solve_linear_program(objective, constraints, rhs): + # Constructing the tableau + tableau = construct_tableau(objective, constraints, rhs) + + # Instantiate the Tableau class + simplex_tableau = Tableau(tableau) + + # Run the simplex algorithm + solution, optimal_value = simplex_tableau.run_simplex() + + # Output the solution + print("Optimal Solution:", solution) + print("Optimal Value:", optimal_value) + +# Example usage +if __name__ == "__main__": + # Coefficients of the objective function: maximize 3x1 + 2x2 + objective = [3, 2] + + # Coefficients of the constraints: + # 2x1 + x2 <= 18 + # x1 + 2x2 <= 20 + constraints = [[2, 1], [1, 2]] + + # Right-hand side of the constraints + rhs = [18, 20] + + # Solve the linear program + solve_linear_program(objective, constraints, rhs) From cda2cf77915370723a01f1b661d191a1b7a74a35 Mon Sep 17 00:00:00 2001 From: MohdFuzailHaider Date: Thu, 10 Oct 2024 16:04:05 +0530 Subject: [PATCH 2/4] Fixed formatting issues --- my_script.py | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/my_script.py b/my_script.py index e9f072a7afc9..a5568807d048 100644 --- a/my_script.py +++ b/my_script.py @@ -1,21 +1,22 @@ import numpy as np + class Tableau: def __init__(self, tableau): self.tableau = tableau self.num_rows, self.num_cols = tableau.shape - + def pivot(self, row, col): # Divide the pivot row by the pivot element self.tableau[row] /= self.tableau[row, col] - + # Subtract multiples of the pivot row from all other rows for i in range(self.num_rows): if i != row: - self.tableau[i] -= self.tableau[i, col] * self.tableau[row] + self.tableau[i] -= (self.tableau[i, col] * self.tableau[row]) def find_pivot_column(self): - # The pivot column is the most negative value in the objective row (row 0) + # The pivot column is the most negative value in the objective row obj_row = self.tableau[0, :-1] pivot_col = np.argmin(obj_row) if obj_row[pivot_col] >= 0: @@ -23,7 +24,7 @@ def find_pivot_column(self): return pivot_col def find_pivot_row(self, pivot_col): - # Calculate the ratios of the right-hand side to the pivot column entries + # Calculate the ratio of the righthand side to the pivotcolumnentries rhs = self.tableau[1:, -1] col = self.tableau[1:, pivot_col] ratios = [] @@ -32,7 +33,7 @@ def find_pivot_row(self, pivot_col): ratios.append(rhs[i] / col[i]) else: ratios.append(np.inf) # Ignore non-positive entries - + pivot_row = np.argmin(ratios) + 1 # Add 1 because we ignored row 0 if np.isinf(ratios[pivot_row - 1]): return -1 # No valid pivot row (unbounded) @@ -47,7 +48,7 @@ def run_simplex(self): pivot_row = self.find_pivot_row(pivot_col) if pivot_row == -1: raise ValueError("Linear program is unbounded.") - + self.pivot(pivot_row, pivot_col) return self.extract_solution() @@ -58,63 +59,66 @@ def extract_solution(self): col = self.tableau[i, :-1] if np.count_nonzero(col) == 1: solution[np.argmax(col)] = self.tableau[i, -1] - return solution, -self.tableau[0, -1] # Return solution and optimal value + return solution, -self.tableau[0, -1] # Returnsolutionandoptimalvalue + def construct_tableau(objective, constraints, rhs): """ Constructs the initial tableau for the simplex algorithm. - + Parameters: - objective: List of coefficients of the objective function (maximize). - constraints: List of lists representing coefficients of the constraints. - rhs: List of right-hand-side values of constraints. - + Returns: - tableau: A numpy array representing the initial simplex tableau. """ n_constraints = len(constraints) n_vars = len(objective) - + # Creating the tableau matrix tableau = np.zeros((n_constraints + 1, n_vars + n_constraints + 1)) - + # Fill the objective function (row 0, cols 0 to n_vars) tableau[0, :n_vars] = -np.array(objective) # Maximization -> negate - + # Fill the constraints for i in range(n_constraints): tableau[i + 1, :n_vars] = constraints[i] tableau[i + 1, n_vars + i] = 1 # Slack variable tableau[i + 1, -1] = rhs[i] # RHS of the constraints - + return tableau + def solve_linear_program(objective, constraints, rhs): # Constructing the tableau tableau = construct_tableau(objective, constraints, rhs) - + # Instantiate the Tableau class simplex_tableau = Tableau(tableau) - + # Run the simplex algorithm solution, optimal_value = simplex_tableau.run_simplex() - + # Output the solution print("Optimal Solution:", solution) print("Optimal Value:", optimal_value) + # Example usage if __name__ == "__main__": # Coefficients of the objective function: maximize 3x1 + 2x2 objective = [3, 2] - + # Coefficients of the constraints: # 2x1 + x2 <= 18 # x1 + 2x2 <= 20 constraints = [[2, 1], [1, 2]] - + # Right-hand side of the constraints rhs = [18, 20] - + # Solve the linear program solve_linear_program(objective, constraints, rhs) From 32c464928e7df1245d0c7515297d0528841d8a5a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 10:38:13 +0000 Subject: [PATCH 3/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- my_script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/my_script.py b/my_script.py index a5568807d048..0f6f3f2aef4e 100644 --- a/my_script.py +++ b/my_script.py @@ -13,7 +13,7 @@ def pivot(self, row, col): # Subtract multiples of the pivot row from all other rows for i in range(self.num_rows): if i != row: - self.tableau[i] -= (self.tableau[i, col] * self.tableau[row]) + self.tableau[i] -= self.tableau[i, col] * self.tableau[row] def find_pivot_column(self): # The pivot column is the most negative value in the objective row From c6885b937f5159e3e75b73ebffb9b8141afd73ee Mon Sep 17 00:00:00 2001 From: MohdFuzailHaider Date: Thu, 10 Oct 2024 16:16:23 +0530 Subject: [PATCH 4/4] Moved my_script.py to scripts folder --- scripts/my_script.py | 124 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 scripts/my_script.py diff --git a/scripts/my_script.py b/scripts/my_script.py new file mode 100644 index 000000000000..a5568807d048 --- /dev/null +++ b/scripts/my_script.py @@ -0,0 +1,124 @@ +import numpy as np + + +class Tableau: + def __init__(self, tableau): + self.tableau = tableau + self.num_rows, self.num_cols = tableau.shape + + def pivot(self, row, col): + # Divide the pivot row by the pivot element + self.tableau[row] /= self.tableau[row, col] + + # Subtract multiples of the pivot row from all other rows + for i in range(self.num_rows): + if i != row: + self.tableau[i] -= (self.tableau[i, col] * self.tableau[row]) + + def find_pivot_column(self): + # The pivot column is the most negative value in the objective row + obj_row = self.tableau[0, :-1] + pivot_col = np.argmin(obj_row) + if obj_row[pivot_col] >= 0: + return -1 # No negative value, we are done + return pivot_col + + def find_pivot_row(self, pivot_col): + # Calculate the ratio of the righthand side to the pivotcolumnentries + rhs = self.tableau[1:, -1] + col = self.tableau[1:, pivot_col] + ratios = [] + for i in range(len(rhs)): + if col[i] > 0: + ratios.append(rhs[i] / col[i]) + else: + ratios.append(np.inf) # Ignore non-positive entries + + pivot_row = np.argmin(ratios) + 1 # Add 1 because we ignored row 0 + if np.isinf(ratios[pivot_row - 1]): + return -1 # No valid pivot row (unbounded) + return pivot_row + + def run_simplex(self): + while True: + pivot_col = self.find_pivot_column() + if pivot_col == -1: + break # Optimal solution found + + pivot_row = self.find_pivot_row(pivot_col) + if pivot_row == -1: + raise ValueError("Linear program is unbounded.") + + self.pivot(pivot_row, pivot_col) + + return self.extract_solution() + + def extract_solution(self): + solution = np.zeros(self.num_cols - 1) + for i in range(1, self.num_rows): + col = self.tableau[i, :-1] + if np.count_nonzero(col) == 1: + solution[np.argmax(col)] = self.tableau[i, -1] + return solution, -self.tableau[0, -1] # Returnsolutionandoptimalvalue + + +def construct_tableau(objective, constraints, rhs): + """ + Constructs the initial tableau for the simplex algorithm. + + Parameters: + - objective: List of coefficients of the objective function (maximize). + - constraints: List of lists representing coefficients of the constraints. + - rhs: List of right-hand-side values of constraints. + + Returns: + - tableau: A numpy array representing the initial simplex tableau. + """ + n_constraints = len(constraints) + n_vars = len(objective) + + # Creating the tableau matrix + tableau = np.zeros((n_constraints + 1, n_vars + n_constraints + 1)) + + # Fill the objective function (row 0, cols 0 to n_vars) + tableau[0, :n_vars] = -np.array(objective) # Maximization -> negate + + # Fill the constraints + for i in range(n_constraints): + tableau[i + 1, :n_vars] = constraints[i] + tableau[i + 1, n_vars + i] = 1 # Slack variable + tableau[i + 1, -1] = rhs[i] # RHS of the constraints + + return tableau + + +def solve_linear_program(objective, constraints, rhs): + # Constructing the tableau + tableau = construct_tableau(objective, constraints, rhs) + + # Instantiate the Tableau class + simplex_tableau = Tableau(tableau) + + # Run the simplex algorithm + solution, optimal_value = simplex_tableau.run_simplex() + + # Output the solution + print("Optimal Solution:", solution) + print("Optimal Value:", optimal_value) + + +# Example usage +if __name__ == "__main__": + # Coefficients of the objective function: maximize 3x1 + 2x2 + objective = [3, 2] + + # Coefficients of the constraints: + # 2x1 + x2 <= 18 + # x1 + 2x2 <= 20 + constraints = [[2, 1], [1, 2]] + + # Right-hand side of the constraints + rhs = [18, 20] + + # Solve the linear program + solve_linear_program(objective, constraints, rhs)