Skip to content

Instantly share code, notes, and snippets.

@marethyu
Created February 11, 2024 22:32
Show Gist options
  • Save marethyu/06a2d0f93aafa0babcc179b82c165dbe to your computer and use it in GitHub Desktop.
Save marethyu/06a2d0f93aafa0babcc179b82c165dbe to your computer and use it in GitHub Desktop.
Simplex method in Python
"""
The function simplex takes initial feasible dictionary of a LP problem with
m basic variables and n non-basic variables, represented by (m+1)x(n+1) matrix
wrapped in numpy.array, as its only input.
The format of the input matrix input is as follows:
In each row, the first column is reserved for additive constant
while the rest of the columns stores coefficients of non-basic variable.
The first row describes the objective function while the rest of the rows
list constraints. You can check some examples near the end of the file.
"""
import numpy as np
def simplex(tableau):
m = tableau.shape[0] - 1
n = tableau.shape[1] - 1
nonbasic_vars = [i for i in range(1, n + 1)]
basic_vars = [n + i for i in range(1, m + 1)]
while True:
print(f'NONBASIC VARS: {nonbasic_vars}')
print(f'BASIC VARS: {basic_vars}')
print(tableau)
entering_idx = -1
leaving_idx = -1
largest_coeff = -348573248583457
min_inc = 8943738945723545
# select entering and leaving variables
for j in range(n, 0, -1):
if tableau[0][j] > 0 and tableau[0][j] >= largest_coeff:
entering_idx = j
largest_coeff = tableau[0][j]
if entering_idx == -1:
print(f'OPTIMAL SOLUTION FOUND!! z={tableau[0][0]}\n')
break
for i in range(m, 0, -1):
if tableau[i][entering_idx] < 0:
x_inc = tableau[i][0] / -tableau[i][entering_idx]
if x_inc <= min_inc:
leaving_idx = i
min_inc = x_inc
if leaving_idx == -1:
print('UNBOUNDED LP PROBLEM!!\n')
break
print(f'ENTERING: x_{nonbasic_vars[entering_idx - 1]}')
print(f'LEAVING: x_{basic_vars[leaving_idx - 1]}')
tmp = basic_vars[leaving_idx - 1]
basic_vars[leaving_idx - 1] = nonbasic_vars[entering_idx - 1]
nonbasic_vars[entering_idx - 1] = tmp
# update dictionary
c = tableau[leaving_idx][entering_idx]
tableau[leaving_idx][entering_idx] = -1
tableau[leaving_idx][:] *= -1 / c
for i in range(0, m + 1):
if i == leaving_idx:
continue
c = tableau[i][entering_idx]
tableau[i][entering_idx] = 0
tableau[i][:] += c * tableau[leaving_idx][:]
# perform bubble sort if needed
run = n
swapped = True
while swapped:
swapped = False
for j in range(1, run):
if nonbasic_vars[j - 1] > nonbasic_vars[j]:
tmp = nonbasic_vars[j - 1]
nonbasic_vars[j - 1] = nonbasic_vars[j]
nonbasic_vars[j] = tmp
tableau[:, [j, j + 1]] = tableau[:, [j + 1, j]]
swapped = True
run -= 1
run = m
swapped = True
while swapped:
swapped = False
for i in range(1, run):
if basic_vars[i - 1] > basic_vars[i]:
tmp = basic_vars[i - 1]
basic_vars[i - 1] = basic_vars[i]
basic_vars[i] = tmp
tableau[[i, i + 1]] = tableau[[i + 1, i]]
swapped = True
run -= 1
print()
# hw2 5a
test1 = np.array([[0, 2, 3, 3],
[60, -3, -1, 0],
[10, 1, -1, -4],
[15, -2, 2, -5]]).astype(float)
# hw2 5b
test2 = np.array([[0, 3, 2, 4],
[4, -1, -1, -2],
[5, -2, 0, -3],
[7, -2, -1, -3]]).astype(float)
# lec6 example
test3 = np.array([[0, 4, 3],
[40, -2, -1],
[30, -1, -1],
[15, -1, 0]]).astype(float)
# lec7 unbounded lp prob. example
test4 = np.array([[10, 1, -1, -2],
[1, 0, -1, -1],
[1, 2, 0, -1],
[1, 1, 1, -1]]).astype(float)
# lec7 another unbounded lp prob. example
test5 = np.array([[0, 0, 2, 1],
[5, -1, 1, -1],
[3, 2, -1, 0],
[5, 0, -1, 2]]).astype(float)
simplex(test1)
simplex(test2)
simplex(test3)
simplex(test4)
simplex(test5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment