# Create a Program to Implement LP Solver in Python Assignment Solution.

## Instructions

Objective
Write a Python program to implement an LP solver and complete a Python assignment. The program will use the Python language to create a solver that can handle linear programming problems efficiently. Linear programming is a mathematical method used to optimize objective functions given certain constraints. By implementing this LP solver, you will gain a deeper understanding of optimization techniques and how to apply them using Python. Completing this Python assignment will not only enhance your programming skills but also equip you with the ability to solve real-world problems more effectively.

## Requirements and Specifications Source Code

```import numpy as np import re def read_data(file_name): """ This function read the coefficients for a LP problem from a file given by file_name :param file_name: Name of the file :return: x: list with the coefficients of the objective function c: list of lists with the coefficients of the constraints b: values of the constants for the constraints """ # First, read the file n_variables = -1 n_constraints = -1 constraints = [] c = [] b = [] r = re.compile(r'([^\t]*)\t*') with open(file_name, 'r') as f: lines = f.readlines() # The first line contains the objective function obj = lines.strip() objs_coeffs = obj.split() x = [float(x) for x in objs_coeffs] # The rest are the constraints for i in range(1, len(lines)): constraint = lines[i].strip() constraints_coeffs = constraint.split() ci = [float(x) for x in constraints_coeffs[:-1]] bi = float(constraints_coeffs[-1]) c.append(ci) b.append(bi) n_variables = len(objs_coeffs) n_constraints = len(c) + n_variables # we add n_variables for the constraints of type x_i >= 0 return x, c, b def getTableau(x, c, b): """ This function builds the Tableay for the Simplex Method :param x: list with the coefficients of the objective function :param c: list of lists with the coefficients of the constraints :param b: values of the constants for the constraints return: 2-D NumPy Array (matrix) """ n = len(c) + 1 # the number of rows is equal to the number of constraints plus one for the objective m = 2*len(x) +1 # the number of coolumns is the double of the number of variable (because of slcak variables) plus one for the equality nvars = len(x) #number of real variables nconst = len(c) # number of constraints # Stack the values of the objective T = np.array(c) # initializw the table with the values of the coefficients of the constraints T = np.hstack((T, np.eye(nconst))) # coefficients for slack variables # Now stack b T = np.column_stack((T, np.array([b]).T)) # Finally, stack the row of the objective obj_row = -np.array(x) # To this row, add the indexes for slack variables obj_row = np.hstack((obj_row, np.zeros(nconst+1))) obj_row[-1]= 1 # Now stack T = np.row_stack((T, obj_row)) return T def isUnbounded(T): """ This function checks if a Tableau T for Simplex Method is unbounded :param T: Tableau (2D NumPy Array) :return: boolean """ # This function checks the Tableau and checks if the problem is unbounded # Examine each column (n, r) = T.shape for j in range(r-1): # iterate through columns except the last one column_ok = False for i in range(n): if T[i,j] <= 0: column_ok = True break if not column_ok: # column has only positive values, so its unbounded return True return False def getPivotColumnIndex(T): """ This functions get the index of the pivot column in T :param T: 2D NumPy Array :return: integer """ # Initialize with the index and minimum value in the first column index = 0 min_val = min(T[:,0]) (n, r) = T.shape # Iterate through columns and get the one with the most negative value for i in range(1,r): val =T[-1,i] if val < min_val: min_val = val index = i return index def getPivotRowIndex(T, pc): """ This function gets the index of the pivt row :param T: 2D NumPy Array :param pc: index of the pivot column :return: integer """ (n,r) = T.shape # Now, divide the pivot column by b and select the index of the min val pivot_col = T[:,pc] b = T[:,-1] # Divide b by the coefficients in the pivot column result = np.zeros(len(b)) for i in range(len(b)): if pivot_col[i] > 0: result[i] = b[i]/pivot_col[i] else: result[i] = np.inf #result = np.divide(b, pivot_col) # Pick the index of the minimum value index = np.argmin(result[:-1]) return index def printTable(T): """ this function prints a 2D NumPy Array in a way easier to look for the user :param T: 2D NumPy Array :return: None """ (n,r) = T.shape for i in range(n): print("[ ", end="") for j in range(r): print("{:.2f}".format(T[i,j]), end= "\t") print("]") if __name__ == '__main__': import sys assert len(sys.argv) > 1, "No arguments passed to script!" file_name = sys.argv """ SIMPLEX METHOD """ # Read data from file x, c, b = read_data(file_name) # Create Table T = getTableau(x, c, b) # Number of variables nvars = len(x) # Define a max number of iterations max_iters = 500 # define a max number of iterations # Shape of table (n, r) = T.shape # Iteration counter iter = 1 # List used to store the index of the columns pivoted pivots = [] solution_flag = 0 # 0 for no solution found, 1 for solution found, 2 for unbounded problem and 3 for infeasible # The followig lines prints the Tableau at the initial status """ print(f"\n\nInitial table") printTable(T) print("\n\n") """ # Start algorithm variables_row = -1*np.ones(T.shape) while True: # Check unbounded if isUnbounded(T): solution_flag = 2 # unbounded break # Get pivot column pc = getPivotColumnIndex(T) """ # if the pivot column is for one of the slack variables, then the method is infeasible if pc > nvars-1: solution_flag = 3 break """ # If the pivot column has only negative values, the problem does not have a solution if len(np.where(T[:,pc] > 0)) == 0: # no positive values, only negative solution_flag = 2 break # Get pivot row pr = getPivotRowIndex(T, pc) # Pivot element pe = T[pr, pc] # Update pivot row T[pr, :] = np.divide(T[pr, :], pe) for i in range(n) : # iterate through rows if i != pr: # not the pivot row pivot_col_coeff = T[i, pc] new_row = T[i,:] - pivot_col_coeff*T[pr,:] T[i,:] = new_row # use the following lines to see the Tableau at each iteration """ print(f"\n\nITER {iter}") printTable(T) print("\n\n") """ pivots.append([pr, pc]) variables_row[pc] = pr # If the last row of the Table has only positive values, it means that the method finished last_row = T[-1,:] if np.all((last_row >= 0)): solution_flag = 1 break iter += 1 if max_iters == iter: # max number of iterations reached. No solution found. Problem should be infeasible solution_flag = 3 break if solution_flag == 1: #printTable(T) # Solution found X = np.zeros(nvars) # Array to store the solutions vars_found = [] # List to store the index of the variables found in the method for i in range(nvars): idx = int(variables_row[i]) if not idx in vars_found and idx < nvars: X[i] = T[idx, -1] vars_found.append(idx) """ for pivot in pivots: X[pivot] = T[pivot, -1] vars_found.append(pivot) """ Z = T[-1, -1] # Value of the objective function # Now, calculate the value of the variable not found directly. s = 0 for i in vars_found: s += x[i] * X[i] # Calculate that variable from the objective for i in range(nvars): if not i in vars_found: X[i] = Z - s # Print print("optimal") print(Z) for x in X: print(x, end=" ") elif solution_flag == 2: print("unbounded") elif solution_flag == 3: print("infeasible")```