diff --git a/learning/learning.py b/learning/learning.py index 4dea7f705c1e4fc28b2c5b90971bda7a75b07ca8..b8b9011265eb2fbd51104e6e3b73373670f4ee65 100644 --- a/learning/learning.py +++ b/learning/learning.py @@ -399,7 +399,7 @@ class LearningAlgorithm: hyp.getChaosDelta()) return hyp - # Get all labels enabled after row + # Get all labels possibly enabled after row def _getAllLabels(self, row, outputs): enabledInputs = self._teacher.getInputAlphabet() enabledOutputs = self._teacher.getOutputAlphabet() diff --git a/learning/observationtable.py b/learning/observationtable.py index 100cad961038e9ae08e1a7c03384945ac057265c..0b69eac9c1cb0ae853b8c51abfc4d3fc2f271d3b 100644 --- a/learning/observationtable.py +++ b/learning/observationtable.py @@ -52,18 +52,21 @@ class Table: # _rows also contains empty trace self._rows = set() self._rows.add(()) - for label in self._possibleInputs((), None): + for label in self._possibleInputs(()): self._rows.add(tuple(label)) # Define the top part of the table (for closedness) self._rowsInS = set() # Empty trace is always in S self._rowsInS.add(()) + + # Define S^e + # S^e is [x for x in self._rows - self._rowsInS if x.isDefined()] # _entries is a dictionary (tuple of actions) -> (set(outputs), set(outputs)) # start with the empty sequence of actions and one letter extensions - self._entries = {():(set(),self._possibleOutputs((), None))} - for label in self._possibleInputs((), None): - self._entries[tuple(label)] = (set(),self._possibleOutputs(tuple(label), None)) + self._entries = {():(set(),self._possibleOutputs(()))} + for label in self._possibleInputs(()): + self._entries[tuple(label)] = (set(),self._possibleOutputs(tuple(label))) # Calculate the preciseness of the table def preciseness(self): @@ -87,7 +90,7 @@ class Table: # Return True if trace is in the table def isInRows(self, trace): - return trace in self._rows + return trace in self._rows and self.isDefined(trace) # Given two rows, check if they belong to the same equivalence class @d.deprecated @@ -210,7 +213,7 @@ class Table: self._logger.warning("Add one letter extensions: "+ str(row) +" is not in the table.") else: outputs, observation = self._entries[row] - for my_input in self._possibleInputs(row, outputs): + for my_input in self._possibleInputs(row): if self.addOneLetterExtension(row, my_input): modified = True for output in outputs: @@ -335,7 +338,7 @@ class Table: enabledRow2.add(self._quiescence) else: outputs = self.getOutputs(current[1]) - enabledInputs = self._possibleInputs(current[1], outputs) + enabledInputs = self._possibleInputs(current[1]) enabledRow2 = outputs.union(enabledInputs) for label in enabledRow2: enabledRow1 = set() @@ -345,7 +348,7 @@ class Table: enabledRow1.add(self._quiescence) else: outputs = self.getOutputs(current[0]) - enabledInputs = self._possibleInputs(current[0], outputs) + enabledInputs = self._possibleInputs(current[0]) enabledRow1 = outputs.union(enabledInputs) if label not in enabledRow1: suffixes = set() @@ -443,7 +446,7 @@ class Table: # get all possible (enabled) labels of row1 outputs = self.getOutputs(row1) - inputs = self._possibleInputs(row1, outputs) + inputs = self._possibleInputs(row1) labels = inputs.union(outputs) @@ -574,7 +577,7 @@ class Table: # get an empty nonfinal entry def _emptyEntry(self, trace): - return (set(), self._possibleOutputs(trace, None)) + return (set(), self._possibleOutputs(trace)) # get an empty final entry def _emptyFinalEntry(self, trace): @@ -682,7 +685,7 @@ class Table: if trace in self._entries: return self._entries[trace][1] else: - return self._possibleOutputs(trace, None) + return self._possibleOutputs(trace) # Update an entry in the table. If it does not exist, create it # observation is the answer of the observation oracle @@ -709,7 +712,7 @@ class Table: # given a trace, query outputPurpose for the outputs that are possibly # enabled after it - def _possibleOutputs(self, trace, outputs): + def _possibleOutputs(self, trace): if self._outputPurpose == None: return self._outputs.union(set((self._quiescence,))) else: @@ -717,7 +720,7 @@ class Table: # given a trace, query inputPurpose for the inputs that are # enabled after it - def _possibleInputs(self, trace, outputs): + def _possibleInputs(self, trace): if self._inputPurpose == None: return self._inputs else: @@ -741,19 +744,20 @@ class Table: # Given two rows, check if the former is more specific than the latter # row1 ⊑ row2 => for each column, row1[column] ⊑ row2[column] def _moreSpecificRow(self, row1, row2, plus=False): - # First: if they do not enable the same inputs, they are not in such - # a relation TODO: should this check be in moreSpecificEntry instead? outputs1 = self._entries[th.flatten(row1,self._quiescence)][0] outputs2 = self._entries[th.flatten(row2,self._quiescence)][0] - inputs1 = self._possibleInputs(th.flatten(row1,self._quiescence), outputs1) - inputs2 = self._possibleInputs(th.flatten(row2,self._quiescence), outputs2) - if inputs1 != inputs2: - return False # If they enable the same inputs, check each entry. for column in self._columns: entry1 = th.flatten(row1 + column, self._quiescence) entry2 = th.flatten(row2 + column, self._quiescence) + # First: if they do not enable the same inputs, they are not in such + # a relation + inputs1 = self._possibleInputs(entry1) + inputs2 = self._possibleInputs(entry2) + if inputs1 != inputs2: + return False + if entry1 not in self._entries and entry2 not in self._entries: # for some reason both entries do not exist. self._logger.warning("Checking relation between "+str(entry1)+ " and "+str(entry2)+": both entries are not defined.")