Skip to content

Commit 8d0ba8e

Browse files
committed
simplex implemented
1 parent f4a4dac commit 8d0ba8e

File tree

4 files changed

+96
-40
lines changed

4 files changed

+96
-40
lines changed
-16 Bytes
Binary file not shown.

linear_programming.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,7 @@ def add_constraint(self, expr_LHS: sympy.core.Expr, comparator: int, expr_RHS: s
167167
"""
168168
assert comparator in COMPARATORS
169169

170-
if (comparator == EQUAL):
171-
self.constraints.append(Constraint(expr_LHS, GREATER_EQUAL, expr_RHS))
172-
self.constraints.append(Constraint(expr_LHS, LESS_EQUAL, expr_RHS))
173-
else:
174-
self.constraints.append(Constraint(expr_LHS, comparator, expr_RHS))
170+
self.constraints.append(Constraint(expr_LHS, comparator, expr_RHS))
175171

176172
# Update flags
177173
self._A_updated = False
@@ -228,11 +224,13 @@ def solve(self, method=SOLVER_SIMPLEX):
228224
if (method == SOLVER_SIMPLEX):
229225
lp_slacked = self.slacken_problem()
230226

231-
simplex(lp_slacked.A, lp_slacked.b, lp_slacked.c)
227+
x_sol = simplex(lp_slacked.A, lp_slacked.b, lp_slacked.c, lp_slacked.vars_slack_amount)
232228

229+
# Cut slack variables
230+
x_sol = x_sol[:lp_slacked.vars_slack_amount]
231+
print(x_sol)
233232

234-
235-
pass
233+
return x_sol
236234

237235
if (method == SOLVER_INTERIOR_POINT_METHOD):
238236
pass

main.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,32 @@
33

44
if __name__ == "__main__":
55

6+
"""
67
lp = LP.LinearProgrammingProblem()
78
x1 = lp.add_variable(1)
89
x2 = lp.add_variable(2)
910
lp.set_objective(LP.MAX, 6 * x1 + 8 * x2)
1011
lp.add_constraint(5 * x1 + 10 * x2, LP.LESS_EQUAL, 60)
1112
lp.add_constraint(4 * x1 + 4 * x2, LP.LESS_EQUAL, 40)
12-
1313
"""
14-
lp = LP.LP()
14+
lp = LP.LinearProgrammingProblem()
1515
x = lp.add_variable(1)
1616
y = lp.add_variable(2)
1717
z = lp.add_variable(3)
1818
lp.set_objective(LP.MAX, x + 2 * y + 3 * z)
1919
lp.add_constraint(x + y, LP.LESS_EQUAL, 20.5)
20-
lp.add_constraint(y + z, LP.GREATER_EQUAL, 20.5)
21-
lp.add_constraint(x + z, LP.GREATER_EQUAL, 30.5)
22-
"""
20+
lp.add_constraint(y + z, LP.LESS_EQUAL, 20.5)
21+
lp.add_constraint(x + z, LP.LESS_EQUAL, 32.5)
22+
2323

2424

2525
x = lp.solve()
2626

2727
print("z = " + str(x @ lp.c))
2828
print("x = " + str(x))
29-
print("iterations = " + str(lp.iterations))
30-
if (len(lp.variables) == 2):
31-
lp.plot_solution_path()
29+
#print("iterations = " + str(lp.iterations))
30+
#if (len(lp.variables) == 2):
31+
# lp.plot_solution_path()
3232

3333

3434

simplex.py

+82-24
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,90 @@
1212
"""
1313

1414

15-
def simplex(A: np.array, b: np.array, c: np.array) -> np.array:
15+
def simplex(A: np.array, b: np.array, c: np.array, slacks_amt: int) -> np.array:
1616
# https://sdu.itslearning.com/ContentArea/ContentArea.aspx?LocationID=17727&LocationType=1&ElementID=589350
17-
x_current = basic_feasible_solution(A, b, c)
18-
print(A, b, c)
19-
20-
## Choosing a pivot
21-
# Pick a non-negative column TODO
22-
positives = np.where(c > 0)
23-
if (not len(positives[0])):
24-
return "All coefficients negative"
25-
26-
x_index = positives[0][0]
27-
y_index = None
28-
29-
val = float("inf")
30-
a = A[:,x_index]
31-
for i in range(b.size):
32-
if (a[i] > 0):
33-
val_current = b[i] / a[i]
34-
if (val_current <= val):
35-
y_index = i
36-
val = val_current
37-
38-
print(y_index)
39-
print(x_index)
17+
#x_current = basic_feasible_solution(A, b, c)
18+
N = [i for i in range(c.size - slacks_amt)] # Not In basis
19+
B = [i for i in range(slacks_amt, c.size)] # In basis
4020

21+
print(A, b, c)
22+
print(N, B)
23+
24+
while True:
25+
## Choosing a pivot
26+
# Pick a non-negative column TODO
27+
positives = np.where(c > 0)
28+
if (not len(positives[0])):
29+
break
30+
31+
xx = positives[0][0]
32+
yy = None
33+
yy_old = None
34+
35+
# Picking smallest row b[i] / a[i]
36+
val = float("inf")
37+
a = A[:,xx]
38+
for i in range(b.size):
39+
if (a[i] > 0):
40+
val_current = b[i] / a[i]
41+
if (val_current <= val):
42+
yy = i
43+
val = val_current
44+
45+
# Find column from where basis was exited
46+
a = A[yy,:]
47+
for i in range(a.size):
48+
if (a[i] == 1):
49+
s = np.sum(A[:,i]) + c[i]
50+
if (s == 1):
51+
yy_old = i
52+
break
53+
# Remove yy_old from basis and add yy to basis
54+
B.remove(yy_old)
55+
B.append(yy)
56+
N.append(yy_old)
57+
N.remove(yy)
58+
59+
## Pivot: A[xx, yy] - Peform row operations
60+
# Set yy row with in column xx to 1
61+
b[yy] = b[yy] * 1 / A[yy, xx]
62+
A = row_mult(A, yy, 1 / A[yy, xx])
63+
64+
# Set column xx in c to 0
65+
c = c - A[yy,:] * c[xx]
66+
67+
# Set other values in column xx to 0
68+
for i in range(A.shape[0]):
69+
if (i == yy):
70+
continue
71+
b[i] = b[i] - A[i, xx] * b[yy]
72+
A = row_add(A, i, yy, -A[yy, xx] * A[i, xx])
73+
74+
# Get solution
75+
x_sol = np.zeros(c.size)
76+
for i in range(len(B)):
77+
x_sol[B[i]] = b[i]
78+
return np.array(x_sol)
79+
80+
def row_mult(A: np.array, row_index: int, scalar: int) -> np.array:
81+
# Row operation: R1 = scalar * R1
82+
# Inspiration: (TODO - optimize)
83+
# https://personal.math.ubc.ca/~pwalls/math-python/linear-algebra/solving-linear-systems/
84+
I = np.eye(A.shape[0])
85+
I[row_index, row_index] = scalar
86+
return I @ A
87+
88+
def row_add(A: np.array, row_main_index: int, row_other_index: int, scalar: int) -> np.array:
89+
# Row operation: R1 = R1 + scalar * R2
90+
# Inspiration: (TODO - optimize)
91+
# https://personal.math.ubc.ca/~pwalls/math-python/linear-algebra/solving-linear-systems/
92+
93+
I = np.eye(A.shape[0])
94+
if (row_main_index == row_other_index):
95+
I[row_main_index, row_main_index] = scalar + 1
96+
else:
97+
I[row_main_index, row_other_index] = scalar
98+
return I @ A
4199

42100
def basic_feasible_solution(A: np.array, b: np.array, c: np.array) -> np.array:
43101
zero_point = zero_point_solution(A, b, c)

0 commit comments

Comments
 (0)