def _get_first_fraction_solution_pivot(self): sol = self.orig_problem_solution int_test = float_comp(sol - np.round(sol), 0.0, equal=True) if np.all(int_test): return None else: col_idx = np.where( np.logical_not(int_test).flat)[0][0] # first fraction # base_columns = SimplexSolver._get_base_columns_indx(self._tableau) # row_idx = np.where(float_comp(self._tableau.A[:, base_columns[col_idx]], 1.0, equal=True).flat)[0][0] row_idx = np.where( float_comp(self._tableau.A[:, col_idx], 1.0, equal=True).flat)[0][0] # return pivot location for canonical fraction solution constraint return row_idx, col_idx
def _choose_pivot_primal(tableau): j = 0 while j < tableau.ct.shape[1] and \ float_comp(tableau.ct[0, j], 0.0, greater=True, equal=True): j += 1 if j < tableau.ct.shape[1]: posit = np.where( float_comp(tableau.A[:, j].flat, 0.0, greater=True)) posit = posit[0] if posit.size == 0: # unbounded return None, j # return the last chosen column else: i = posit[np.argmin(tableau.b[posit, 0] / tableau.A[posit, j])] return i, j else: return None # No element in (-c)^t negative
def _choose_pivot_dual(tableau): i = 0 while i < tableau.b.shape[0] and \ float_comp(tableau.b[i, 0], 0.0, greater=True, equal=True): i += 1 if i < tableau.b.shape[0]: negat = np.where(float_comp(tableau.A[i, :].flat, 0.0, less=True)) negat = negat[0] if negat.size == 0: # infeasible return i, None else: j = negat[np.argmin(tableau.ct[0, negat] / (-1 * tableau.A[i, negat]))] return i, j else: return None # No element in b negative
def _get_fraction_solution_idx(self): sol = self.orig_problem_solution int_test = float_comp(sol - np.round(sol), 0.0, equal=True) if np.all(int_test): return None else: return np.where( np.logical_not(int_test).flat)[0][0] # first fraction solution
def is_pivot_column(columns): columns = np.asarray(columns, np.float64) ret = np.empty(columns.shape[1], np.bool) for j in np.arange(0, columns.shape[1]): line_equal_one = np.isclose(columns[:, j], [1.0]) # only one line with 1.0 ret[j] = line_equal_one.sum() == 1 # all other lines with 0.0 ret[j] = ret[j] and np.all( float_comp( columns[np.logical_not(line_equal_one), j], 0.0, equal=True)) return ret
def run_simplex(self, fout=None): # need auxiliary tableau? if np.any(float_comp(self._tableau.ct, 0.0, less=True)) and \ np.any(float_comp(self._tableau.b, 0.0, less=True)): aux_tableau = self._build_aux_tableau() num_cons = aux_tableau.A.shape[0] base_columns = np.arange(-num_cons, 0) SimplexSolver._update_ct_to_canonical_form(aux_tableau, base_columns, fout) self._run_simplex(aux_tableau, fout) if np.all(float_comp(aux_tableau.obj, 0.0, equal=False)): # Infeasible LP self.lp_type = "infeasible" self._certificate = aux_tableau.yt.T return else: num_cons = aux_tableau.A.shape[0] # updating the original tableau with the contents of the aux tableau self._tableau.mat[1:, :] = np.hstack( (aux_tableau.mat[1:, :-(num_cons + 1)], aux_tableau.b)) bcols = SimplexSolver._get_base_columns_indx(aux_tableau) SimplexSolver._update_ct_to_canonical_form( self._tableau, bcols, fout) last_pivot = self._run_simplex(self._tableau, fout) if last_pivot is None: # Bounded LP self.lp_type = "bounded" self._certificate = self._tableau.yt.T else: # Unbounded or Infeasible LP if last_pivot[0] is not None: # Infeasible LP self.lp_type = "infeasible" self._certificate = self._tableau.op[last_pivot[0], :].T elif last_pivot[1] is not None: # Unbounded LP self.lp_type = "unbounded" self._certificate = self._calc_unbounded_certificate( last_pivot[1]) else: raise Exception("Result from simplex not expected")
def _run_solver_recursive(self, best_solution, fout=None): super().run_simplex(fout) if self.lp_type == "bounded": fract_sol_idx = self._get_fraction_solution_idx() if fract_sol_idx is None: if best_solution is None or self.objvalue > best_solution.obj[ 0, 0]: return self._tableau else: if best_solution is None or self.objvalue > best_solution.obj[ 0, 0]: # if not prunning orig_tableau = self._tableau orig_certificate = self._certificate sol = self.orig_problem_solution row_pivot = np.where( float_comp(self._tableau.A[:, fract_sol_idx], 1.0, equal=True).flat)[0][0] new_cons = np.zeros((1, orig_tableau.num_vars + 2), np.float64) new_cons[0, -2] = 1.0 new_cons[0, fract_sol_idx] = 1.0 new_cons[0, -1] = np.floor(sol[fract_sol_idx]) new_tableau_less = deepcopy(orig_tableau) new_tableau_less.add_constraint(new_cons) new_tableau_less.mat = gausselim.pivoting( new_tableau_less.mat, row_pivot + 1, fract_sol_idx + new_tableau_less.op.shape[1]) self._tableau = new_tableau_less best_solution = self._run_solver_recursive( best_solution, fout) new_cons[0, fract_sol_idx] = -1.0 new_cons[0, -1] = -np.ceil(sol[fract_sol_idx]) new_tableau_greater = deepcopy(orig_tableau) new_tableau_greater.add_constraint(new_cons) new_tableau_greater.mat = gausselim.pivoting( new_tableau_greater.mat, row_pivot + 1, fract_sol_idx + new_tableau_greater.op.shape[1]) self._tableau = new_tableau_greater best_solution = self._run_solver_recursive( best_solution, fout) self._tableau = orig_tableau self._certificate = orig_certificate return best_solution
def _build_aux_tableau(self): num_cons = self._tableau.A.shape[0] aux_c = np.zeros_like(self._tableau.ct) aux_c = np.asmatrix( np.hstack((np.zeros((1, num_cons)), aux_c, np.ones( (1, num_cons)))), np.float64) b_neglines = np.where(float_comp(self._tableau.b, 0.0, less=True))[0] opmat = np.asmatrix(np.identity(num_cons), np.float64) aux_opA = np.hstack((opmat, self._tableau.A)) aux_opA[b_neglines, :] = aux_opA[b_neglines, :] * (-1) aux_opA = np.hstack((aux_opA, np.identity(aux_opA.shape[0]))) aux_b = np.copy(self._tableau.b) aux_b[b_neglines, :] = aux_b[b_neglines, :] * (-1) aux_tab_mat = np.vstack((np.hstack( (aux_c, [[0.0]])), np.hstack((aux_opA, aux_b)))) aux_tab = Tableau(aux_tab_mat) return aux_tab
def _get_base_columns_indx(tableau): base_columns = np.where(float_comp(tableau.ct, 0.0, equal=True))[1] base_columns = base_columns[gausselim.is_pivot_column( tableau.A[:, base_columns])] return base_columns
def _choose_pivot(tableau): if np.alltrue(float_comp(tableau.ct, 0.0, greater=True, equal=True)): return SimplexSolver._choose_pivot_dual(tableau) if np.alltrue(float_comp(tableau.b, 0.0, greater=True, equal=True)): return SimplexSolver._choose_pivot_primal(tableau)