diff --git a/src/simplexe.py b/src/simplexe.py index c6631f1b1d1a3da928d50a2c7e21960ee9362240..12de09f20d4c1e3bef367c787334829b03a8a72d 100644 --- a/src/simplexe.py +++ b/src/simplexe.py @@ -30,6 +30,10 @@ class Simplexe: self.NumRows = self.AMatrix.shape[0] self.NumCols = self.AMatrix.shape[1] + self.hasCycle = False + + # self.initBasicVariable = self.__basicVariables.copy() + def SolveProblem(self): self.__start = time.time() self.__initTableau() @@ -166,6 +170,9 @@ class Simplexe: self.__tableau = np.append(self.__tableau, tmpC, axis=0) self.__basicVariables = np.arange( self.NumCols, self.NumCols + self.NumRows, 1, dtype=int) + + self.__initBasicVariable = self.__basicVariables.copy() + self.TableauRowCount, self.TableauColCount = self.__tableau.shape for rowId in range(self.NumRows): if self.__tableau[rowId, -1] < -Constants.EPS: @@ -176,6 +183,7 @@ class Simplexe: # returns next pivot as an array of leaving row id and entering col Id # return None if there is pivot (sets optimisation status accoringly before returning) def __selectPivot(self): + # print(self.__basicVariables) colId = self.__selectEnteringColumn() if ((not colId) | colId < 0): # no more entering column => optimiser status is OPTIMAL (must be - we never select a pivot if the tableau is unfeasible) @@ -188,6 +196,13 @@ class Simplexe: self.OptStatus = OptStatus.NotBounded return None # normal case : we do have a standard pivot! + # print(f"Before : {self.__basicVariables}") + # print(f"RowID = {rowId}") + # idx_to_replace = np.argwhere(self.__basicVariables == rowId)[0][0] + self.__basicVariables[rowId] = colId + # print(f"After : {self.__basicVariables}") + # print(idx_to_replace) + return [rowId, colId] def __getBasicVariableValue(self, rowId, baseColId): @@ -249,7 +264,6 @@ class Simplexe: ################################################################### # returns cheks if the current solution is feasible or not (return True if feasible) - def __isSolutionFeasible(self): # we MUST have that all BASIC variables are >= 0 to have a FEASIBLE solution # to iterate over basic variables do: @@ -270,20 +284,25 @@ class Simplexe: # print(self.__tableau[rowId, baseColId]) # - # This maybe ain't that dumb but it works half the time which is weird - # if self.__PivotCount > self.AMatrix.shape[1] - 1: - # return -1 - # - # return self.__PivotCount + if np.array_equal(self.__basicVariables, self.__initBasicVariable): + self.hasCycle = True + + if self.hasCycle: + for idx, val in enumerate(self.__tableau[-1, :-1]): + if val < 0: + return idx - if np.size(self.__tableau[-1, :-1][np.where(self.__tableau[-1, :-1] - < 0)]) == 0: return -1 + else: + if np.size(self.__tableau[-1, :-1][np.where(self.__tableau[-1, :-1] + < 0)]) == 0: + return -1 - return np.argmin(self.__tableau[-1, :-1]) + return np.argmin(self.__tableau[-1, :-1]) # returns leaving row ID # return None or -1 if there is pivot (sets optimisation status accoringly before returning) + def __selectLeavingRow(self, pivotColId): # given the entering column, find the leaving row - return the index of the row or -1 if none is found # iterate using : @@ -305,6 +324,25 @@ class Simplexe: return candidates.argmin() + # minRatio = float('inf') + # leavingRow = -1 + # + # rowCount = self.TableauRowCount - 2 if self.IsPhaseI else \ + # self.TableauRowCount - 1 + # + # for index in range(rowCount): + # # Si le ration est positif + # if self.__tableau[index][pivotColId] > 0: + # ratio = self.__tableau[index][-1] / \ + # self.__tableau[index][pivotColId] + # if ratio < minRatio: + # minRatio = ratio + # leavingRow = index + # + # print("leaving row :", leavingRow) # vérification ok + # + # return leavingRow + def __pivotTableau(self, pivotIDs): if pivotIDs is None or pivotIDs[0] < 0 or pivotIDs[1] < 0: # no pivot => optimiser status is updated in pivot selection => return!