def __computesP(self, hypothesis): if hypothesis is None: raise Exception("Hypothesis cannot be None") self._logger.debug("Computing P") P = [] empty_word = Word([EmptyLetter()]) current_query = OutputQuery(empty_word) P.append(current_query) open_queries = deque([current_query]) close_queries = [] seen_states = set([hypothesis.initial_state]) while len(open_queries) > 0: query = open_queries.popleft() tmp_seen_states = set() for letter in self.input_letters: new_word = query.input_word + Word([letter]) query_z = OutputQuery(new_word) (output_word, visited_states) = hypothesis.play_query(query_z) close_queries.append(query_z) if visited_states[-1] not in seen_states: tmp_seen_states.add(visited_states[-1]) open_queries.append(query_z) seen_states.update(tmp_seen_states) P.extend(close_queries) return P
def __is_prefixes_equivalent(self, eq_words_in_S): """This method checks that the specified prefixes are equivalent. It returns None, if all the prefixes share the same row value given any input letters it get suffixed with Returns the letter that makes the eq_words_in_S not equivalent """ if len(eq_words_in_S) < 2: raise Exception("At least two words must be provided") self._logger.debug("Checking if words '{}' are equivalents".format( ','.join([str(s) for s in eq_words_in_S]))) for input_letter in self.input_letters: initial_suffixed_word = Word(eq_words_in_S[0].letters + [input_letter]) for eq_word_in_S in eq_words_in_S[1:]: eq_suffixed_word = Word(eq_word_in_S.letters + [input_letter]) for word_in_D in self.D: self._logger.debug(type(word_in_D)) if self.ot_content[word_in_D][ eq_suffixed_word] != self.ot_content[word_in_D][ initial_suffixed_word]: return (input_letter, word_in_D) return None
def __add_word_in_S(self, word): """Add the specified word in S. In details, it does the following: - add the specified word in the list of words in S - executes the output queries (word + word_in_D) and store the results in DxS - recomputes new SAs made with the specified word + word_in_D >>> from pylstar.ObservationTable import ObservationTable >>> from pylstar.KnowledgeBase import KnowledgeBase >>> from pylstar.Letter import Letter >>> from pylstar.Word import Word >>> kbase = KnowledgeBase() >>> ot = ObservationTable(input_letters = [], knowledge_base = kbase) >>> ot.initialize() >>> w = Word([Letter("a")]) >>> ot._ObservationTable__add_word_in_S(w) """ if word is None: raise Exception("Word cannot be None") if word in self.S: raise Exception( "Word '{}' is already registered in S".format(word)) if word in self.SA: raise Exception( "Word '{}' is already registered in SA".format(word)) self._logger.debug("Registering word '{}' in S".format(word)) self.S.append(word) for word_in_D in self.D: cel = self.ot_content[word_in_D] # if word in cel.keys(): # raise Exception("Word '{}' already exists in observation table with D='{}'".format(word, word_in_D)) # formulates a new OutputQuery and execute it output_query = OutputQuery(word + word_in_D) self._logger.debug("Execute query : {}".format(output_query)) self.__execute_query(output_query) if not output_query.is_queried(): raise Exception( "Query '{}' could not be queried".format(output_query)) cel[word] = output_query.output_word.last_letter() for input_letter in self.input_letters: if isinstance(word.letters[0], EmptyLetter): new_word = Word([input_letter]) else: new_word = word + Word([input_letter]) self._logger.debug("Adding word: {}".format(new_word)) if new_word not in self.S: self.__add_word_in_SA(new_word)
def isCounterExample(self, r_h, r_m): """Return True if the two rewards r_h and r_m are different and add the counter example at the OT.""" if r_m != r_h: print("CE", r_m, r_h, self.observation_seq) input_word = Word( [Letter(symbol) for symbol in self.observation_seq]) output_word = Word( [Letter(symbol) for symbol in self.reward_trace]) self.OT.add_counterexample(input_word, output_word) return True return False
def initialize(self): self._logger.debug("Initialization of the observation table" "") if self.initialized: raise Exception("Observation table is already initialized") self.initialized = True self.D = [] self.S = [] self.SA = [] self.ot_content = dict() # creates a word for each input letter and register it in D for letter in self.input_letters: self.__add_word_in_D(Word([letter])) # creates a word that contains an EmptyLetter and registers it in S self.__add_word_in_S(Word([EmptyLetter()]))
def find_counterexample(self, hypothesis): if hypothesis is None: raise Exception("Hypothesis cannot be None") self._logger.info("Starting the RandomWalk Algorithm to search for a counter-example") i_step = 0 first_step_after_restart = True current_state = hypothesis.initial_state input_word = Word() hypothesis_output_word = Word() force_restart = False while i_step < self.max_steps: # should we restart if not first_step_after_restart: if force_restart or random.random() < self.restart_probability: current_state = hypothesis.initial_state first_step_after_restart = True counterexample_query = self.__check_equivalence(input_word, hypothesis_output_word) if counterexample_query is not None: return counterexample_query input_word = Word() hypothesis_output_word = Word() force_restart = False else: first_step_after_restart = False try: (new_state, input_letter, output_letter) = self.__walk(current_state) current_state = new_state input_word.letters.append(input_letter) hypothesis_output_word.letters.append(output_letter) except Exception as e: self._logger.warn(e) force_restart = True i_step += 1
def __compute_distinguishable_string(self, hypothesis, couple): self._logger.debug( "Computes the distinguishable string for state couple '{}'".format( couple)) if hypothesis is None: raise Exception("Hypothesis cannot be None") if couple is None: raise Exception("couple cannot be None") self._logger.debug( "Computing distinguishing strings for states {}".format(couple)) queries_to_test = deque([]) empty_word = Word([EmptyLetter()]) z_query = OutputQuery(empty_word) for letter in self.input_letters: new_word = z_query.input_word + Word([letter]) queries_to_test.append(OutputQuery(new_word)) distinguishable_query = z_query done = False i = 0 while not done: query = queries_to_test.popleft() if i > self.max_states * self.max_states: break if not self.__is_distinguishable_states(hypothesis, query, couple): done = False for letter in self.input_letters: new_query = OutputQuery(query.input_word + Word([letter])) queries_to_test.append(new_query) else: done = True distinguishable_query = query i = i + 1 return distinguishable_query
def get_output_word(self, input_word): if input_word is None: raise Exception("Input word cannot be None") for root in self.roots: try: w = Word(root.traverse(input_word.letters)) self._logger.info("I = {} > O = {}".format(input_word, w)) return w except Exception: pass raise Exception("No path found")
def submit_word(self, word): """This method return the Word produced by the target while submited the specified word""" output_letters = [] for letter in word.letters: symbols = letter.symbols try: output_symbols = [] for symbol in symbols: try: self.abstraction_layer.writeSymbol(symbol) except ChannelDownException as e: self._logger.debug("Channel is Down") (curr_output_symbols, data) = self.abstraction_layer.readSymbols() output_symbols.extend(curr_output_symbols) output_letters.append(Letter(symbols=output_symbols)) except Exception as e: self._logger.fatal("An error occurred : {}".format(e)) output_letters.append(Letter(symbols=[EmptySymbol()])) for i in range(len(word.letters)): input_letter = word.letters[i] output_letter = output_letters[i] input_str = "None" output_str = "None" if input_letter.symbols is not None: input_str = ','.join([s.name for s in input_letter.symbols]) if output_letter.symbols is not None: output_str = ','.join([s.name for s in output_letter.symbols]) self._logger.debug(">>> {}".format(input_str)) self._logger.debug("<<< {}".format(output_str)) self.write_cache() if self.submitted_word_cb is not None: try: self.submitted_word_cb(word.letters, output_letters) except Exception as e: self._logger.error( "Error encountered while executed submitted_word_cb: {}". format(e)) return Word(output_letters, normalize=False)
def submit_word(self, word): self._logger.debug( "Submiting word '{}' to the fake target".format(word)) if self.automata is None: raise Exception("Automata cannot be None") current_state = self.automata.initial_state output_letters = [] for letter in word.letters: try: (current_state, output_letter) = self._next_state(current_state, letter) except Exception: output_letter = EmptyLetter() output_letters.append(output_letter) output_word = Word(output_letters) return output_word
def submit_word(self, word): self._logger.debug( "Submiting word '{}' to the network target".format(word)) output_letters = [] s = socket.socket() # Reuse the connection s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.settimeout(self.timeout) s.connect((self.target_host, self.target_port)) try: output_letters = [ self._submit_letter(s, letter) for letter in word.letters ] finally: s.close() return Word(letters=output_letters)
def _execute_word(self, word): # Executes the specified word. if word is None: raise Exception("Word cannot be None") self._logger.debug("Execute word '{}'".format(word)) #print("Execute word '{}'".format(word)) reward_trace = [] self.nuof_MQs += 1 self.world.mrm.reset() self.world.map.reset() ge = GetExperience(self.world, word, MODE) #Create the scheduler i = 0 while i < len(word): letter = word.letters[i] a = ge.getActionScheduler(self.world.map.current, i) #ask for the next action to execute (obs, rew) = self.world.moveAPF(a) #get observation and reward reset = False while Letter(obs) != letter: if obs == "null": #if we observe nothing execute a new action self.actionsForLearning += 1 a = ge.getActionScheduler(self.world.map.current, i) (obs, rew) = self.world.moveAPF(a) else: #if we observe something we don't want, reset reset = True break if reset: self.world.reset() i = 0 reward_trace = [] else: #if we observe what we want i += 1 reward_trace.append(rew) w = Word([Letter(r) for r in reward_trace]) return w
def __computesZ(self, hypothesis, W): """it follows the formula Z= W U (X^1.W) U .... U (X^(m-1-n).W) U (W^(m-n).W) """ if hypothesis is None: raise Exception("Hypothesis cannot be None") if W is None: raise Exception("W cannot be None") self._logger.debug("Computing Z") Z = [] Z.extend(W) states = hypothesis.get_states() v = self.max_states - len(states) if v < 0: v = 0 self._logger.debug("V= {}".format(v)) output_queries = [] for input_letter in self.input_letters: output_query = OutputQuery(word=Word([input_letter])) output_queries.append(output_query) X = dict() X[0] = W for i in range(1, v + 1): self._logger.debug("Computing X^{}".format(i)) X[i] = [] previous_X = X[i - 1] for x in previous_X: X[i].extend(x.multiply(output_queries)) for w in W: for xi in X[i]: if not xi in Z: Z.append(xi) return Z
def play_word(self, input_word, starting_state=None): """This method can be used to play the specified word across the current automata. It returns a tuple made of the output_word and the visited state captured while visiting the automata >>> from pylstar import Letter, EmptyLetter >>> from pylstar import Word >>> from pylstar import State >>> from pylstar import Transition >>> from pylstar import Automata >>> l_lambda = EmptyLetter() >>> l_a = Letter('a') >>> l_b = Letter('b') >>> l_0 = Letter(0) >>> l_1 = Letter(1) >>> s0 = State("S0") >>> s1 = State("S1") >>> s2 = State("S2") >>> s3 = State("S3") >>> t1 = Transition("T1", s3, l_a, l_0) >>> t2 = Transition("T2", s1, l_b, l_0) >>> s0.transitions = [t1, t2] >>> t3 = Transition("T3", s0, l_a, l_1) >>> t4 = Transition("T4", s2, l_b, l_1) >>> s1.transitions = [t3, t4] >>> t5 = Transition("T5", s3, l_a, l_0) >>> t6 = Transition("T6", s0, l_b, l_0) >>> s2.transitions = [t5, t6] >>> t7 = Transition("T7", s3, l_a, l_1) >>> t8 = Transition("T8", s3, l_b, l_1) >>> s3.transitions = [t7, t8] >>> automata = Automata(s0) >>> print(automata.play_word(Word([l_a, l_a, l_a]))[0]) [Letter(0), Letter(1), Letter(1)] >>> print(automata.play_word(Word([l_b, l_b, l_b]))[0]) [Letter(0), Letter(1), Letter(0)] >>> print(automata.play_word(Word([l_b, l_a, l_b, l_a, l_b]))[0]) [Letter(0), Letter(1), Letter(0), Letter(1), Letter(0)] """ if input_word is None or len(input_word) == 0: raise Exception("Input word cannot be None or empty") if starting_state is None: current_state = self.initial_state else: current_state = starting_state self._logger.debug("Playing word '{}'".format(input_word)) output_letters = [] visited_states = [] for letter in input_word.letters: (output_letter, output_state) = current_state.visit(letter) output_letters.append(output_letter) visited_states.append(output_state) current_state = output_state output_word = Word(letters=output_letters) return (output_word, visited_states)
def build_hypothesis(self): """This method returns and Automata that follows the observation table. If the observation table is closed and consistent, it is possible to construct an hypothesis automata. Each state of the automata maps to a row of S in the observation table. >>> from pylstar.ObservationTable import ObservationTable >>> from pylstar.KnowledgeBase import KnowledgeBase >>> from pylstar.Letter import Letter, EmptyLetter >>> from pylstar.Word import Word >>> l_lambda = EmptyLetter() >>> l_a = Letter('a') >>> l_b = Letter('b') >>> l_y = Letter('y') >>> l_z = Letter('z') >>> w_lambda = Word([l_lambda]) >>> w_a = Word([l_a]) >>> w_b = Word([l_b]) >>> w_aa = Word([l_a, l_a]) >>> w_ab = Word([l_a, l_b]) >>> w_aaa = Word([l_a, l_a, l_a]) >>> w_aab = Word([l_a, l_a, l_b]) >>> kbase = KnowledgeBase() >>> ot = ObservationTable(input_letters = [l_a, l_b], knowledge_base = kbase) >>> ot.D.extend([w_a, w_b, w_aa]) >>> ot.S.extend([w_lambda, w_a, w_aa]) >>> ot.SA.extend([w_b, w_ab, w_aaa, w_aab]) >>> ot.ot_content[w_a] = dict() >>> ot.ot_content[w_a][w_lambda] = l_z >>> ot.ot_content[w_a][w_a] = l_y >>> ot.ot_content[w_a][w_aa] = l_z >>> ot.ot_content[w_a][w_b] = l_y >>> ot.ot_content[w_a][w_ab] = l_z >>> ot.ot_content[w_a][w_aaa] = l_z >>> ot.ot_content[w_a][w_aab] = l_y >>> ot.ot_content[w_b] = dict() >>> ot.ot_content[w_b][w_lambda] = l_z >>> ot.ot_content[w_b][w_a] = l_y >>> ot.ot_content[w_b][w_aa] = l_z >>> ot.ot_content[w_b][w_b] = l_y >>> ot.ot_content[w_b][w_ab] = l_z >>> ot.ot_content[w_b][w_aaa] = l_z >>> ot.ot_content[w_b][w_aab] = l_y >>> ot.ot_content[w_aa] = dict() >>> ot.ot_content[w_aa][w_lambda] = l_y >>> ot.ot_content[w_aa][w_a] = l_z >>> ot.ot_content[w_aa][w_aa] = l_z >>> ot.ot_content[w_aa][w_b] = l_z >>> ot.ot_content[w_aa][w_ab] = l_y >>> ot.ot_content[w_aa][w_aaa] = l_y >>> ot.ot_content[w_aa][w_aab] = l_z >>> print(ot) | [Letter('a')] | [Letter('b')] | [Letter('a'), Letter('a')] --------------------------------------- | ------------- | ------------- | -------------------------- [EmptyLetter] | Letter('z') | Letter('z') | Letter('y') [Letter('a')] | Letter('y') | Letter('y') | Letter('z') [Letter('a'), Letter('a')] | Letter('z') | Letter('z') | Letter('z') ~~~ | ~~~ | ~~~ | ~~~ [Letter('b')] | Letter('y') | Letter('y') | Letter('z') [Letter('a'), Letter('b')] | Letter('z') | Letter('z') | Letter('y') [Letter('a'), Letter('a'), Letter('a')] | Letter('z') | Letter('z') | Letter('y') [Letter('a'), Letter('a'), Letter('b')] | Letter('y') | Letter('y') | Letter('z') --------------------------------------- | ------------- | ------------- | -------------------------- >>> print(ot.is_closed()) True >>> print(ot.find_inconsistency()) None >>> automata = ot.build_hypothesis() >>> print(automata.build_dot_code()) digraph "Automata" { "0" [shape=doubleoctagon, style=filled, fillcolor=white, URL="0"]; "1" [shape=ellipse, style=filled, fillcolor=white, URL="1"]; "2" [shape=ellipse, style=filled, fillcolor=white, URL="2"]; "0" -> "1" [fontsize=5, label="a / z", URL="t0"]; "0" -> "1" [fontsize=5, label="b / z", URL="t1"]; "1" -> "2" [fontsize=5, label="a / y", URL="t2"]; "1" -> "0" [fontsize=5, label="b / y", URL="t3"]; "2" -> "0" [fontsize=5, label="a / z", URL="t4"]; "2" -> "1" [fontsize=5, label="b / z", URL="t5"]; } """ states = [] transitions = [] initial_state = None words_and_states = [] long_state_name_to_states = dict() # find all rows in S rows_in_S = [(s, self.__get_row(s)) for s in self.S] # get all unique rows S_with_same_rows = collections.OrderedDict() for word_in_s, row_s in rows_in_S: key = ','.join([str(w) for w in row_s]) if key not in S_with_same_rows.keys(): S_with_same_rows[key] = list() S_with_same_rows[key].append(word_in_s) # build the list of states of the hypothesis (and identify the initial state) for long_state_name, words_in_S in S_with_same_rows.items(): state_name = str( len(states) ) #''.join(long_state_name.replace("Letter(", "").replace(')', '')) state = State(name=state_name) states.append(state) words_and_states.append((words_in_S[0], state)) long_state_name_to_states[long_state_name] = state # check if its the initial state epsilon_word_found = Word([EmptyLetter()]) in words_in_S self._logger.debug("state :{} , {} / {}".format( long_state_name, words_in_S, epsilon_word_found)) if initial_state is None and epsilon_word_found: initial_state = state elif epsilon_word_found and initial_state is not None: raise Exception("Multiple initial state found.") if initial_state is None: raise Exception("Can't find any initial state") # computes the transitions for each state of the automata for word, state in words_and_states: for input_letter in self.input_letters: # computes the output state new_word = word + Word([input_letter]) row_new_word = self.__get_row(new_word) output_state_name = ','.join([str(w) for w in row_new_word]) if output_state_name not in long_state_name_to_states.keys(): for x in long_state_name_to_states.keys(): self._logger.debug(x) raise Exception( "Cannot find a state with following name : '{}'". format(output_state_name)) output_state = long_state_name_to_states[output_state_name] output_letter = self.ot_content[Word([input_letter])][word] transition_name = "t{}".format(len(transitions)) transition = Transition(name=transition_name, output_state=output_state, input_letter=input_letter, output_letter=output_letter) state.transitions.append(transition) transitions.append(transition) return Automata(initial_state=initial_state)
def buildProductAutomaton(self, h): """Given a hypothesis of the angluin algo, build the product between the gird and this hypothesis and write it in a PRISM file. The init state is {'c1','r1','null'} with no obs already made""" rewards = "rewards\n" labels = '' out_file = open(TMP_MODEL_PATH, 'w') #module out_file.write("mdp\n\nmodule tmp\n\n") #number of state and initial state new_states = [] for s in self.world.map.states: for o in range(len(h.get_states())): labels += 'label "' + s + '_' + str(o) + '" = s=' + str( len(new_states)) + ' ;\n' new_states.append((s, o)) out_file.write("\ts : [0.." + str(len(new_states) - 1) + "] init " + str(new_states.index((self.world.map.initiales[0], 0))) + ";\n\n") #transitions for s in new_states: state_id = self.world.map.getIdState(s[0]) for a in self.world.map.availableActions(s[0]): action_id = self.world.map.getIdAction(a) obs = self.world.map.labelling[state_id][action_id] #if len(self.world.map.transitions[state_id][action_id]) > 0: out_file.write("\t[" + a + "] s=" + str(new_states.index(s)) + "-> ") temp_list = [] if obs == 'null': rewards += "\t[" + a + "] (s=" + str( new_states.index(s)) + ") : " + str( self.world.mrm.default_reward) + ";\n" for [dest, prob ] in self.world.map.transitions[state_id][action_id]: index_dest = str( new_states.index( (self.world.map.getStateFromId(dest), s[1]))) temp_list.append( str(prob) + " : (s'=" + index_dest + ")") else: tr_val = h.play_word( Word([Letter(obs)]), self.getStateInHypothesis(h.get_states(), s[1])) state_in_h = int(tr_val[1][-1].name) rewards += "\t[" + a + "] (s=" + str( new_states.index(s)) + ") : " + str( tr_val[0].last_letter().name) + ";\n" for [dest, prob ] in self.world.map.transitions[state_id][action_id]: index_dest = str( new_states.index( (self.world.map.getStateFromId(dest), state_in_h))) temp_list.append( str(prob) + " : (s'=" + index_dest + ")") out_file.write(" + ".join(temp_list)) out_file.write(";\n") a = "reset" out_file.write( "\t[" + a + "] s=" + str(new_states.index(s)) + "-> 1.0 : (s'=" + str(new_states.index((self.world.map.initiales[0], 0))) + ");\n") rewards += "\t[" + a + "] (s=" + str( new_states.index(s)) + ") : " + str( self.world.mrm.reset_cost) + ";\n" out_file.write("\nendmodule\n\n") out_file.write(labels) rewards += "endrewards\n" out_file.write(rewards) out_file.close()
def make_consistent(self, inconsistency): """This method makes consistent the observation table. >>> from pylstar.ObservationTable import ObservationTable >>> from pylstar.FakeActiveKnowledgeBase import FakeActiveKnowledgeBase >>> from pylstar.Letter import Letter, EmptyLetter >>> from pylstar.Word import Word >>> from pylstar.automata.State import State >>> from pylstar.automata.Transition import Transition >>> from pylstar.automata.Automata import Automata >>> l_lambda = EmptyLetter() >>> l_a = Letter('a') >>> l_b = Letter('b') >>> l_0 = Letter(0) >>> l_1 = Letter(1) >>> s0 = State("S0") >>> s1 = State("S1") >>> s2 = State("S2") >>> s3 = State("S3") >>> t1 = Transition("T1", s3, l_a, l_0) >>> t2 = Transition("T2", s1, l_b, l_0) >>> s0.transitions = [t1, t2] >>> t3 = Transition("T3", s0, l_a, l_1) >>> t4 = Transition("T4", s2, l_b, l_1) >>> s1.transitions = [t3, t4] >>> t5 = Transition("T5", s3, l_a, l_0) >>> t6 = Transition("T6", s0, l_b, l_0) >>> s2.transitions = [t5, t6] >>> t7 = Transition("T7", s3, l_a, l_1) >>> t8 = Transition("T8", s3, l_b, l_1) >>> s3.transitions = [t7, t8] >>> automata = Automata(s0) >>> kbase = FakeActiveKnowledgeBase(automata) >>> ot = ObservationTable(input_letters = [l_a, l_b], knowledge_base = kbase) >>> ot.initialize() >>> print(ot) | [Letter('a')] | [Letter('b')] ------------- | ------------- | ------------- [EmptyLetter] | Letter(0) | Letter(0) ~~~ | ~~~ | ~~~ [Letter('a')] | Letter(1) | Letter(1) [Letter('b')] | Letter(1) | Letter(1) ------------- | ------------- | ------------- >>> print(ot.is_closed()) False >>> ot.close_table() >>> print(ot) | [Letter('a')] | [Letter('b')] -------------------------- | ------------- | ------------- [EmptyLetter] | Letter(0) | Letter(0) [Letter('a')] | Letter(1) | Letter(1) ~~~ | ~~~ | ~~~ [Letter('b')] | Letter(1) | Letter(1) [Letter('a'), Letter('a')] | Letter(1) | Letter(1) [Letter('a'), Letter('b')] | Letter(1) | Letter(1) -------------------------- | ------------- | ------------- >>> counter_input_word = Word([l_b, l_b, l_b]) >>> counter_output_word = Word([l_0, l_1, l_0]) >>> ot.add_counterexample(counter_input_word, counter_output_word) >>> print(ot) | [Letter('a')] | [Letter('b')] ---------------------------------------------------- | ------------- | ------------- [EmptyLetter] | Letter(0) | Letter(0) [Letter('a')] | Letter(1) | Letter(1) [Letter('b')] | Letter(1) | Letter(1) [Letter('b'), Letter('b')] | Letter(0) | Letter(0) [Letter('b'), Letter('b'), Letter('b')] | Letter(0) | Letter(0) ~~~ | ~~~ | ~~~ [Letter('a'), Letter('a')] | Letter(1) | Letter(1) [Letter('a'), Letter('b')] | Letter(1) | Letter(1) [Letter('b'), Letter('a')] | Letter(0) | Letter(0) [Letter('b'), Letter('b'), Letter('a')] | Letter(1) | Letter(1) [Letter('b'), Letter('b'), Letter('b'), Letter('a')] | Letter(1) | Letter(1) [Letter('b'), Letter('b'), Letter('b'), Letter('b')] | Letter(1) | Letter(1) ---------------------------------------------------- | ------------- | ------------- >>> inconsistency = ot.find_inconsistency() >>> ot.make_consistent(inconsistency) >>> inconsistency = ot.find_inconsistency() >>> if inconsistency is not None: ot.make_consistent(inconsistency) >>> print(ot.find_inconsistency()) None >>> print(ot.is_closed()) True >>> automata = ot.build_hypothesis() >>> print(automata.build_dot_code()) digraph "Automata" { "0" [shape=doubleoctagon, style=filled, fillcolor=white, URL="0"]; "2" [shape=ellipse, style=filled, fillcolor=white, URL="2"]; "3" [shape=ellipse, style=filled, fillcolor=white, URL="3"]; "1" [shape=ellipse, style=filled, fillcolor=white, URL="1"]; "0" -> "1" [fontsize=5, label="a / 0", URL="t0"]; "0" -> "2" [fontsize=5, label="b / 0", URL="t1"]; "2" -> "0" [fontsize=5, label="a / 1", URL="t4"]; "2" -> "3" [fontsize=5, label="b / 1", URL="t5"]; "3" -> "1" [fontsize=5, label="a / 0", URL="t6"]; "3" -> "0" [fontsize=5, label="b / 0", URL="t7"]; "1" -> "1" [fontsize=5, label="a / 1", URL="t2"]; "1" -> "1" [fontsize=5, label="b / 1", URL="t3"]; } """ if inconsistency is None: raise Exception("Inconsistency cannot be None") # verify both words of inconsistency share the same last letter suffix = inconsistency[0][1] inconsistent_suffix = inconsistency[1] new_col_word = Word([suffix] + inconsistent_suffix.letters) self.__add_word_in_D(new_col_word)
def add_counterexample(self, input_word, output_word): """This method register the specified counterexample in the observation table. In details, it insert all the prefixes of the counterexample to the upper part of the table. It also extend SA accordingly. >>> from pylstar.ObservationTable import ObservationTable >>> from pylstar.FakeActiveKnowledgeBase import FakeActiveKnowledgeBase >>> from pylstar.Letter import Letter, EmptyLetter >>> from pylstar.Word import Word >>> from pylstar.automata.State import State >>> from pylstar.automata.Transition import Transition >>> from pylstar.automata.Automata import Automata >>> l_lambda = EmptyLetter() >>> l_a = Letter('a') >>> l_b = Letter('b') >>> l_0 = Letter(0) >>> l_1 = Letter(1) >>> s0 = State("S0") >>> s1 = State("S1") >>> s2 = State("S2") >>> s3 = State("S3") >>> t1 = Transition("T1", s3, l_a, l_0) >>> t2 = Transition("T2", s1, l_b, l_0) >>> s0.transitions = [t1, t2] >>> t3 = Transition("T3", s0, l_a, l_1) >>> t4 = Transition("T4", s2, l_b, l_1) >>> s1.transitions = [t3, t4] >>> t5 = Transition("T5", s3, l_a, l_0) >>> t6 = Transition("T6", s0, l_b, l_0) >>> s2.transitions = [t5, t6] >>> t7 = Transition("T7", s3, l_a, l_1) >>> t8 = Transition("T8", s3, l_b, l_1) >>> s3.transitions = [t7, t8] >>> automata = Automata(s0) >>> kbase = FakeActiveKnowledgeBase(automata) >>> ot = ObservationTable(input_letters = [l_a, l_b], knowledge_base = kbase) >>> ot.initialize() >>> print(ot) | [Letter('a')] | [Letter('b')] ------------- | ------------- | ------------- [EmptyLetter] | Letter(0) | Letter(0) ~~~ | ~~~ | ~~~ [Letter('a')] | Letter(1) | Letter(1) [Letter('b')] | Letter(1) | Letter(1) ------------- | ------------- | ------------- >>> print(ot.is_closed()) False >>> ot.close_table() >>> print(ot) | [Letter('a')] | [Letter('b')] -------------------------- | ------------- | ------------- [EmptyLetter] | Letter(0) | Letter(0) [Letter('a')] | Letter(1) | Letter(1) ~~~ | ~~~ | ~~~ [Letter('b')] | Letter(1) | Letter(1) [Letter('a'), Letter('a')] | Letter(1) | Letter(1) [Letter('a'), Letter('b')] | Letter(1) | Letter(1) -------------------------- | ------------- | ------------- >>> counter_input_word = Word([l_b, l_b, l_b]) >>> counter_output_word = Word([l_0, l_1, l_0]) >>> ot.add_counterexample(counter_input_word, counter_output_word) >>> print(ot) | [Letter('a')] | [Letter('b')] ---------------------------------------------------- | ------------- | ------------- [EmptyLetter] | Letter(0) | Letter(0) [Letter('a')] | Letter(1) | Letter(1) [Letter('b')] | Letter(1) | Letter(1) [Letter('b'), Letter('b')] | Letter(0) | Letter(0) [Letter('b'), Letter('b'), Letter('b')] | Letter(0) | Letter(0) ~~~ | ~~~ | ~~~ [Letter('a'), Letter('a')] | Letter(1) | Letter(1) [Letter('a'), Letter('b')] | Letter(1) | Letter(1) [Letter('b'), Letter('a')] | Letter(0) | Letter(0) [Letter('b'), Letter('b'), Letter('a')] | Letter(1) | Letter(1) [Letter('b'), Letter('b'), Letter('b'), Letter('a')] | Letter(1) | Letter(1) [Letter('b'), Letter('b'), Letter('b'), Letter('b')] | Letter(1) | Letter(1) ---------------------------------------------------- | ------------- | ------------- """ if input_word is None or len(input_word) == 0: raise Exception("Input word cannot be None or empty") if output_word is None or len(output_word) == 0: raise Exception("Output word cannot be None or empty") if len(input_word) != len(output_word): raise Exception( "Output word must have the same length then input word") for len_prefix in range(1, len(input_word) + 1): prefix_input = Word(input_word.letters[:len_prefix]) if prefix_input not in self.S: if prefix_input in self.SA: self.remove_row(prefix_input) self.__add_word_in_S(prefix_input)