-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsimplex.js
211 lines (177 loc) · 6.93 KB
/
simplex.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/**
* Function that performs simplex row operations on A and b.
*
* @param A 2d array of LHS constraint coefficients.
* @param b 1d array of solution values.
* @param x 1d decision variable array.
* @param xB 1d basis variable array.
* @param pivColIdx Pivot column index.
* @param pivRowIdx Pivot row index.
* @param pivEl Pivot element.
* @param pivCol Pivot column.
* @param mn Number of columns in A.
* @param m Number of rows in A.
* @return Updated A, b, xB.
*/
function rowOps(A, b, x, xB, pivColIdx, pivRowIdx, pivEl, pivCol, mn, m) {
// Divide pivot row by pivot element
b[pivRowIdx] /= pivEl;
// Replace pivot row basis variable with pivot column variable
xB[pivRowIdx] = x[pivColIdx];
// Loop over columns
for (let i = 0; i < mn; i++) {
// Divide pivot row by pivot element
A[pivRowIdx][i] /= pivEl;
// Loop over rows
for (let j = 0; j < m; j++) {
// b subtraction should only be done once per row
if (j != pivRowIdx) {
// Only one column in b
if (i == 0) {
b[j] -= pivCol[j] * b[pivRowIdx];
}
// Subtract what multiple of the corrected pivot row is
// required to get zeros in all columns corresponding to
// basis variables
A[j][i] -= pivCol[j] * A[pivRowIdx][i];
}
}
}
// Return updated arrays
return [A, b, xB];
}
/**
* Performs a singe iteration of simplex and calls genTableau on the previous
* iteration. All inputs pertain to the values from the previous iteration of
* simplex.
*
* @param A 2d array of constraint coefficients.
* @param b 1d array of solution values.
* @param cj Objective function coefficients.
* @param x 1d array of decision variable names.
* @param xB 1d array of basis variable names.
* @param zc 1d array of zj-cj row contents.
* @return [A, b, xB, isUnbounded, isPermInf]
*/
function simplex(A, b, cj, x, xB, zc) {
// Initialize dimensionality variables
var {m, mn} = getDims(A);
// Initialize Booleans
var isPermInf = false;
var isAltSol = false;
var befAltSol = false;
var {minIndex, isFeas, isOptim} = isOptAndFeas(b, zc);
// Adjust algorithm used depending on whether problem is feasible or not
if (!isFeas) {
var [k, pivCol, ratio, pivEl, pivColIdx, pivRowIdx] =
findInfPivots(A, zc, minIndex, pivColIdx, m, mn);
// If k is still 0 then no elements of A[minIndex] that were less than
// 0 were found
if (k == 0) {
isPermInf = true;
}
// Infeasible problems by definition do not satisfy the criteria as is
// for unboundedness
var isUnbounded = false;
} else if (!isOptim) {
// Method for working with non-optimal, but feasible solutions
// If the problem is feasible, it's not permanently infeasible
isPermInf = false;
// Obtain pivot information
var [pivEl, pivCol, pivColIdx, pivRowIdx, ratio, isUnbounded] =
findPivots(A, b, zc);
}
// Tabulate previous iteration
var bools = new Bools(isFeas, isOptim, isUnbounded, isPermInf,
isAltSol, befAltSol);
genTableau(A, b, cj, x, xB, bools, pivCol, ratio, pivEl,
pivRowIdx, pivColIdx);
// Time to exit function if permanently infeasible, as there's no way
// to solve the problem
if (isPermInf) {
return [A, b, xB, isUnbounded, isPermInf];
}
// Apply feasible problem simplex algorithm
if (pivRowIdx >= 0 && pivRowIdx < m) {
[A, b, xB] = rowOps(A, b, x, xB, pivColIdx, pivRowIdx, pivEl,
pivCol, mn, m);
}
// Return data needed by simplexIterator
return [A, b, xB, isUnbounded, isPermInf];
}
/**
* Performs all the iterations of simplex required to find the
* optimum solution.
*
* @param A 2d array of constraint coefficients.
* @param b 1d array of constraint RHS.
* @param cj 1d array of objective function coefficients.
* @param x 1d array of decision variable names.
* @param xB 1d array of basis variable names.
* @param sign What the objective function has been multiplied by to
* make it max, either 1 (max problem) or -1 (min problem).
* @param objVarName Name of the objective function (usually just a letter).
* @return [A, b, cj, x, xB, z]
*/
function simplexIterator(A, b, cj, x, xB, sign, objVarName) {
// Error messages
dimsCheck(A, b, cj, x, xB);
// Initialize global variables
var {zj, zc} = calcEntries(A, b, cj, x, xB);
var {isFeas, isOptim} = isOptAndFeas(b, zc);
var isUnbounded = false;
var isPermInf = false;
// If problem is already optimal, just tabulate the solution
if (isOptim) {
tempStr += "Solution is already optimal.";
// Draw final tableau
genTableau(A, b, cj, x, xB, {isFeas: isFeas, isOptim: isOptim});
// Update finals before showSolution, in case there's alt sol
updateFinals(A, b, cj, x, xB, zj, zc);
// Show solution
showSolution(A, b, cj, x, xB, zj, zc, sign, objVarName);
}
// Use simplex to solve the problem
while ((!isOptim) && (!isUnbounded) && (!isPermInf)) {
var arr = simplex(A, b, cj, x, xB, zc);
[A, b, xB, isUnbounded, isPermInf] = arr;
// Calculate zj and zj-cj
var {zj, zc} = calcEntries(A, b, cj, x, xB);
// Determine whether problem is now optimal and feasible
var {isFeas, isOptim} = isOptAndFeas(b, zc);
// Show an appropriate message if the problem is infeasible or
// unbounded
if (isUnbounded) {
tempStr += "Problem is unbounded! ";
} else if (isPermInf) {
tempStr += "Problem is infeasible! ";
return [A, b, cj, x, xB, zj, false];
} else if (isOptim) {
// Update finals before showSolution, in case there's alt sol
updateFinals(A, b, cj, x, xB, zj, zc);
// Tabulate solution
genTableau(A, b, cj, x, xB, {isFeas: isFeas, isOptim: isOptim});
// Show solution
showSolution(A, b, cj, x, xB, zj, zc, sign, objVarName);
}
}
// Update final values
return [A, b, cj, x, xB, zj, zc, true];
}
/**
* Apply simplexIterator() to arguments obtained from getParameters()
*
* @params None.
* @return Nothing.
*/
function solveProblem() {
// Obtain required problem parameters
var [A, b, cj, x, xB, shouldDie, sign, objVarName] = getParameters();
// Solve problem using simplex iterator
if (!shouldDie) {
[A, b, cj, x, xB, zj, zc, isFeas] = simplexIterator(A, b, cj, x, xB,
sign, objVarName);
}
// Write tempStr to tableau element
document.getElementById("tableau").innerHTML = tempStr;
}