Finds the pivot row and column. >>> tuple(int(x) for x in Tableau(np.array([[-2,1,0,0,0], [3,1,1,0,6], ... [1,2,0,1,7.]]), 2, 0).find_pivot()) (1, 0)
(self)
| 106 | return titles |
| 107 | |
| 108 | def find_pivot(self) -> tuple[Any, Any]: |
| 109 | """Finds the pivot row and column. |
| 110 | >>> tuple(int(x) for x in Tableau(np.array([[-2,1,0,0,0], [3,1,1,0,6], |
| 111 | ... [1,2,0,1,7.]]), 2, 0).find_pivot()) |
| 112 | (1, 0) |
| 113 | """ |
| 114 | objective = self.objectives[-1] |
| 115 | |
| 116 | # Find entries of highest magnitude in objective rows |
| 117 | sign = (objective == "min") - (objective == "max") |
| 118 | col_idx = np.argmax(sign * self.tableau[0, :-1]) |
| 119 | |
| 120 | # Choice is only valid if below 0 for maximise, and above for minimise |
| 121 | if sign * self.tableau[0, col_idx] <= 0: |
| 122 | self.stop_iter = True |
| 123 | return 0, 0 |
| 124 | |
| 125 | # Pivot row is chosen as having the lowest quotient when elements of |
| 126 | # the pivot column divide the right-hand side |
| 127 | |
| 128 | # Slice excluding the objective rows |
| 129 | s = slice(self.n_stages, self.n_rows) |
| 130 | |
| 131 | # RHS |
| 132 | dividend = self.tableau[s, -1] |
| 133 | |
| 134 | # Elements of pivot column within slice |
| 135 | divisor = self.tableau[s, col_idx] |
| 136 | |
| 137 | # Array filled with nans |
| 138 | nans = np.full(self.n_rows - self.n_stages, np.nan) |
| 139 | |
| 140 | # If element in pivot column is greater than zero, return |
| 141 | # quotient or nan otherwise |
| 142 | quotients = np.divide(dividend, divisor, out=nans, where=divisor > 0) |
| 143 | |
| 144 | # Arg of minimum quotient excluding the nan values. n_stages is added |
| 145 | # to compensate for earlier exclusion of objective columns |
| 146 | row_idx = np.nanargmin(quotients) + self.n_stages |
| 147 | return row_idx, col_idx |
| 148 | |
| 149 | def pivot(self, row_idx: int, col_idx: int) -> np.ndarray: |
| 150 | """Pivots on value on the intersection of pivot row and column. |