class LearnSimpleDFA(unittest.TestCase): def setUp(self): s1 = DFAState('s1') s2 = DFAState('s2') s3 = DFAState('s3') s1.add_edge('a', s2) s1.add_edge('b', s1) s2.add_edge('a', s2) s2.add_edge('b', s3) s3.add_edge('a', s3) s3.add_edge('b', s3) self.dfa = DFA(s1, [s3]) def test_lstar_wmethod(self): eqc = WmethodEquivalenceChecker(self.dfa, m=len(self.dfa.get_states())) teacher = Teacher(self.dfa, eqc) learner = LStarDFALearner(teacher) hyp = learner.run() equivalent, _ = eqc.test_equivalence(hyp) self.assertTrue(equivalent) self.assertEqual( len(self.dfa.get_states()), len(hyp.get_states()), ) def test_lstar_bruteforce(self): eqc = BFEquivalenceChecker(self.dfa, max_depth=len(self.dfa.get_states())) teacher = Teacher(self.dfa, eqc) learner = LStarDFALearner(teacher) hyp = learner.run() equivalent, _ = WmethodEquivalenceChecker(self.dfa, m=len(self.dfa.get_states())).test_equivalence(hyp) self.assertTrue(equivalent) self.assertEqual( len(self.dfa.get_states()), len(hyp.get_states()), ) def test_ttt_wmethod(self): eqc = WmethodEquivalenceChecker(self.dfa, m=len(self.dfa.get_states())) teacher = Teacher(self.dfa, eqc) learner = TTTDFALearner(teacher) hyp = learner.run() equivalent, _ = eqc.test_equivalence(hyp) self.assertTrue(equivalent) self.assertEqual( len(self.dfa.get_states()), len(hyp.get_states()), ) def test_ttt_bruteforce(self): eqc = BFEquivalenceChecker(self.dfa, max_depth=len(self.dfa.get_states())) teacher = Teacher(self.dfa, eqc) learner = TTTDFALearner(teacher) hyp = learner.run() equivalent, _ = WmethodEquivalenceChecker(self.dfa, m=len(self.dfa.get_states())).test_equivalence(hyp) self.assertTrue(equivalent) self.assertEqual( len(self.dfa.get_states()), len(hyp.get_states()), )
def setUp(self): s1 = DFAState('s1') s2 = DFAState('s2') s3 = DFAState('s3') s1.add_edge('a', s2) s1.add_edge('b', s1) s2.add_edge('a', s2) s2.add_edge('b', s3) s3.add_edge('a', s3) s3.add_edge('b', s3) self.dfa = DFA(s1, [s3])
def construct_hypothesis(self): # Keep track of the initial state initial_state = self.S[()] # Keep track of the amount of states, so we can sift again if # the sifting process created a new state n = len(list(self.S.items())) items_added = True # Todo: figure out a neater way to handle missing states during sifting than to just redo the whole thing while items_added: # Add transitions for access_seq, cur_state in list(self.S.items()): for a in self.A: next_state = self.sift(access_seq + a) output = self.query(access_seq + a) cur_state.add_edge(a[0], next_state, override=True) # Check if no new state was added n2 = len((self.S.items())) items_added = n != n2 # print("items added", items_added) n = n2 # Find accepting states accepting_states = [ state for access_seq, state in self.S.items() if self.query(access_seq) ] return DFA(initial_state, accepting_states)
def setUp(self): # Set up an example mealy machine s1 = DFAState('1') s2 = DFAState('2') s3 = DFAState('3') s1.add_edge('a', s2) s1.add_edge('b', s1) s2.add_edge('a', s3) s2.add_edge('b', s1) s3.add_edge('a', s3) s3.add_edge('b', s1) self.dfa = DFA(s1, [s3])
def get_dset_outputs(fsm, dset): states = fsm.get_states() outputs = {} for state in states: if isinstance(fsm, MealyMachine): mm = MealyMachine(state) elif isinstance(fsm, DFA): mm = DFA(state, fsm.accepting_states) out = [] for dseq in dset: out.append(mm.process_input(dseq)) mm.reset() outputs[state] = tuple(out.copy()) return outputs
def build_dfa(self): # Gather states from S S = self.S # The rows can function as index to the 'state' objects state_rows = set([tuple(self._get_row(s)) for s in S]) initial_state_row = tuple(self._get_row(tuple())) accepting_states_rows = set( [tuple(self._get_row(s)) for s in S if self.query(s)]) # Generate state names for convenience state_names = { state_row: f's{n + 1}' for (n, state_row) in enumerate(state_rows) } # Build the state objects and get the initial and accepting states states = { state_row: DFAState(state_names[state_row]) for state_row in state_rows } initial_state = states[initial_state_row] accepting_states = [states[a_s] for a_s in accepting_states_rows] # Add the connections between states A = [a for (a, ) in self.A] # Keep track of states already visited visited_rows = [] for s in S: s_row = tuple(self._get_row(s)) if s_row not in visited_rows: for a in A: sa_row = tuple(self._get_row(s + (a, ))) if sa_row in states.keys(): try: states[s_row].add_edge(a, states[sa_row]) except: # Can't add the same edge twice pass else: visited_rows.append(s_row) return DFA(initial_state, accepting_states)
from stmlearn.equivalencecheckers import BFEquivalenceChecker from stmlearn.learners import TTTDFALearner from stmlearn.suls import DFA, DFAState from stmlearn.teachers import Teacher # Set up a simple state machine (S1) =a> (S2) =b> ((S3)) s1 = DFAState('s1') s2 = DFAState('s2') s3 = DFAState('s3') s1.add_edge('a', s2) s2.add_edge('b', s3) sm = DFA(s1, [s3]) # Since we are learning a DFA, we need edges for the whole alphabet in every state s1.add_edge('b', s1) s2.add_edge('a', s2) s3.add_edge('a', s3) s3.add_edge('b', s3) # We are using the brute force equivalence checker eqc = BFEquivalenceChecker(sm) # Set up the teacher, with the system under learning and the equivalence checker teacher = Teacher(sm, eqc) # Set up the learner who only talks to the teacher learner = TTTDFALearner(teacher)
def setUp(self): # Set up an example mealy machine s1 = DFAState('1') s1.add_edge('a', s1) s1.add_edge('b', s1) self.dfa = DFA(s1, [])