def test_active_lstar_05(self): """ Try to let L* learn the regular language A. A is a language over the alphabet sigma = {a}, that accepts all strings with an odd number of a's. """ q0 = automaton.State('0') q1 = automaton.State('1') expected_dfa = automaton.DFA({'a'}, start_state=q0) expected_dfa.add_transition(q0, q1, 'a') expected_dfa.add_transition(q1, q0, 'a') expected_dfa.accept_states.add(q1) teacher = oracle.ActiveOracle(expected_dfa) lstar = algorithms.LSTAR({'a'}, teacher) dfa = lstar.learn() self.assertEqual(2, len(dfa.states)) self.assertEqual(1, len(dfa.accept_states)) s_plus = set() s_minus = set() for i in range(1, 21, 2): s_plus.add('a' * i) s_minus.add('a' * (i - 1)) for s in s_plus: self.assertTrue(dfa.parse_string(s)[1]) for s in s_minus: self.assertFalse(dfa.parse_string(s)[1])
def test_active_nlstar_11(self): """ try to let NL* learn the regular language L. L is a regular language over the alphabet {a, b} where for every string in L contains exactly two a's. """ q0 = automaton.State('0') q1 = automaton.State('1') q2 = automaton.State('2') q3 = automaton.State('3') expected_dfa = automaton.DFA({'a', 'b'}, start_state=q0) expected_dfa.add_transition(q0, q0, 'b') expected_dfa.add_transition(q0, q1, 'a') expected_dfa.add_transition(q1, q1, 'b') expected_dfa.add_transition(q1, q2, 'a') expected_dfa.add_transition(q2, q2, 'b') expected_dfa.add_transition(q2, q3, 'a') expected_dfa.add_transition(q3, q3, 'a') expected_dfa.add_transition(q3, q3, 'b') expected_dfa.accept_states.add(q2) teacher = oracle.ActiveOracle(expected_dfa) nlstar = algorithms.NLSTAR({'a', 'b'}, teacher) nfa = nlstar.learn() dfa = nfa.to_dfa() self.assertEqual(expected_dfa, dfa)
def test_active_lstar_06(self): """ try to let L* learn the regular language A. A is a regular language over the alphabet {0, 1} where each string contains an odd number of 1s """ q0 = automaton.State('0') q1 = automaton.State('1') expected_dfa = automaton.DFA({'0', '1'}, start_state=q0) expected_dfa.add_transition(q0, q0, '0') expected_dfa.add_transition(q0, q1, '1') expected_dfa.add_transition(q1, q1, '0') expected_dfa.add_transition(q1, q0, '1') expected_dfa.accept_states.add(q1) teacher = oracle.ActiveOracle(expected_dfa) lstar = algorithms.LSTAR({'0', '1'}, teacher) dfa = lstar.learn() s_plus = set() s_minus = {''} for i in self._combinations({'0', '1'}, 7): if i.count('1') % 2 == 1: s_plus.add(i) else: s_minus.add(i) for s in s_plus: self.assertTrue(dfa.parse_string(s)[1]) for s in s_minus: self.assertFalse(dfa.parse_string(s)[1])
def test_active_nlstar_07(self): """ try to let NL* learn the regular language A. A is a regular language over the alphabet {0, 1} where each string contains 101 as a substring. """ q1 = automaton.State('1') q2 = automaton.State('2') q3 = automaton.State('3') q4 = automaton.State('4') expected_dfa = automaton.DFA({'0', '1'}, start_state=q1) expected_dfa.add_transition(q1, q1, '0') expected_dfa.add_transition(q1, q2, '1') expected_dfa.add_transition(q2, q2, '1') expected_dfa.add_transition(q2, q3, '0') expected_dfa.add_transition(q3, q1, '0') expected_dfa.add_transition(q3, q4, '1') expected_dfa.add_transition(q4, q4, '0') expected_dfa.add_transition(q4, q4, '1') expected_dfa.accept_states.add(q4) teacher = oracle.ActiveOracle(expected_dfa) nlstar = algorithms.NLSTAR({'0', '1'}, teacher) nfa = nlstar.learn() dfa = nfa.to_dfa() self.assertEqual(expected_dfa.rename_states(), dfa.rename_states())
def test_active_lstar_08(self): """ try to let L* learn the regular language A. A is a regular language over the alphabet {0, 1} where each string contains an even number of 0's and an even number of 1's. """ q1 = automaton.State('1') q2 = automaton.State('2') q3 = automaton.State('3') q4 = automaton.State('4') expected_dfa = automaton.DFA({'a', 'b'}, start_state=q1) expected_dfa.add_transition(q1, q2, 'b') expected_dfa.add_transition(q1, q4, 'a') expected_dfa.add_transition(q2, q1, 'b') expected_dfa.add_transition(q2, q3, 'a') expected_dfa.add_transition(q3, q2, 'a') expected_dfa.add_transition(q3, q4, 'b') expected_dfa.add_transition(q4, q3, 'b') expected_dfa.add_transition(q4, q1, 'a') expected_dfa.accept_states.add(q1) teacher = oracle.ActiveOracle(expected_dfa) lstar = algorithms.LSTAR({'a', 'b'}, teacher) dfa = lstar.learn() self.assertTrue(expected_dfa, dfa)
def test_active_nlstar_05(self): """ Try to let NL* learn the regular language A. A is a language over the alphabet sigma = {a}, that accepts all strings with an odd number of a's. """ q0 = automaton.State('0') q1 = automaton.State('1') expected_dfa = automaton.DFA({'a'}, start_state=q0) expected_dfa.add_transition(q0, q1, 'a') expected_dfa.add_transition(q1, q0, 'a') expected_dfa.accept_states.add(q1) teacher = oracle.ActiveOracle(expected_dfa) nlstar = algorithms.NLSTAR({'a'}, teacher) nfa = nlstar.learn() self.assertEqual(2, len(nfa._states)) self.assertEqual(1, len(nfa._accept_states)) self.assertEqual(expected_dfa, nfa.to_dfa())
def test_active_nlstar_06(self): """ try to let NL* learn the regular language A. A is a regular language over the alphabet {0, 1} where each string contains an odd number of 1s """ q0 = automaton.State('0') q1 = automaton.State('1') expected_dfa = automaton.DFA({'0', '1'}, start_state=q0) expected_dfa.add_transition(q0, q0, '0') expected_dfa.add_transition(q0, q1, '1') expected_dfa.add_transition(q1, q1, '0') expected_dfa.add_transition(q1, q0, '1') expected_dfa.accept_states.add(q1) teacher = oracle.ActiveOracle(expected_dfa) nlstar = algorithms.NLSTAR({'0', '1'}, teacher) nfa = nlstar.learn() self.assertEqual(2, len(nfa._states)) self.assertEqual(1, len(nfa._accept_states)) self.assertEqual(expected_dfa, nfa.to_dfa())
def test_active_lstar_09(self): """ try to let L* learn the regular language L. L is a regular language over the alphabet {a, b, c} where every string in L is an even length. """ q0 = automaton.State('0') q1 = automaton.State('1') expected_dfa = automaton.DFA({'a', 'b', 'c'}, start_state=q0) expected_dfa.add_transition(q0, q1, 'a') expected_dfa.add_transition(q0, q1, 'b') expected_dfa.add_transition(q0, q1, 'c') expected_dfa.add_transition(q1, q0, 'a') expected_dfa.add_transition(q1, q0, 'b') expected_dfa.add_transition(q1, q0, 'c') expected_dfa.accept_states.add(q0) teacher = oracle.ActiveOracle(expected_dfa) lstar = algorithms.LSTAR({'a', 'b', 'c'}, teacher) dfa = lstar.learn() self.assertEqual(expected_dfa, dfa.rename_states())
def _build_automaton(self, ot: utils.ObservationTable) -> automaton.DFA: """ Builds an automaton from the observation table. :type ot: ObservationTable :return: Automaton built from the observation table :rtype: Automaton """ dfa = automaton.DFA(self._alphabet) states = {automaton.State(i) for i in self._red} we = utils.break_strings_in_two(self._red) for w, e in we: we = w + e if we in self._red and ot.entry_exists(w, e): val = ot.get(w, e) state = automaton.State(we) if val == 1: dfa.accept_states.add(state) states.add(state) elif val == 0: dfa.reject_states.add(state) states.add(state) for w in states: for a in self._alphabet: for u in self._red: wa = w.name + a if ot.row_exists(u) and ot.row_exists(wa) and \ ot.get_row(u) == ot.get_row(wa): dfa.add_transition(w, automaton.State(u), a) return dfa
def test_active_lstar_01(self): q0 = automaton.State('0') q1 = automaton.State('1') q2 = automaton.State('2') q3 = automaton.State('3') q4 = automaton.State('4') expected_dfa = automaton.DFA({'a', 'b'}, start_state=q0) expected_dfa.add_transition(q0, q1, 'a') expected_dfa.add_transition(q0, q2, 'b') expected_dfa.add_transition(q1, q3, 'a') expected_dfa.add_transition(q1, q4, 'b') expected_dfa.add_transition(q2, q3, 'a') expected_dfa.add_transition(q2, q3, 'b') expected_dfa.add_transition(q4, q2, 'a') expected_dfa.add_transition(q4, q3, 'b') expected_dfa.add_transition(q3, q3, 'a') expected_dfa.add_transition(q3, q3, 'b') expected_dfa.accept_states.update({q0, q1, q2, q4}) teacher = oracle.ActiveOracle(expected_dfa) lstar = algorithms.LSTAR({'a', 'b'}, teacher) dfa = lstar.learn()
def test_nfa_01(self): nfa = automaton.NFA({'0', '1'}) q1 = automaton.State('q1') q2 = automaton.State('q2') q3 = automaton.State('q3') q4 = automaton.State('q4') nfa.add_state(q1) nfa.add_state(q2) nfa.add_state(q3) nfa.add_state(q4) nfa.add_transition(q1, q1, '0') nfa.add_transition(q1, q1, '1') nfa.add_transition(q1, q2, '1') nfa.add_transition(q2, q3, '0') nfa.add_transition(q2, q3, '') nfa.add_transition(q3, q4, '1') nfa.add_transition(q4, q4, '0') nfa.add_transition(q4, q4, '1') nfa.add_accepting_state(q4) nfa.add_start_state(q1) state, accepted = nfa.parse_string('010110') self.assertTrue(accepted) self.assertEqual(state.name, 'q4')
def test_automaton_02(self): start_state = automaton.State('') q1 = automaton.State('1') q2 = automaton.State('2') dfa = automaton.DFA({'a', 'b'}, start_state) dfa.add_transition(start_state, start_state, 'a') dfa.add_transition(start_state, q1, 'b') dfa.add_transition(q1, q2, 'a') dfa.add_transition(q1, q2, 'b') self.assertEqual(3, len(dfa.states)) self.assertEqual(2, len(dfa._transitions.keys())) self.assertTrue(dfa.transition_exists(start_state, 'a')) self.assertTrue(dfa.transition_exists(start_state, 'b')) self.assertTrue(dfa.transition_exists(q1, 'a')) self.assertFalse(dfa.transition_exists(q2, 'a')) self.assertFalse(dfa.transition_exists(q2, 'b')) q, a = dfa.find_transition_to_q(start_state) self.assertEqual('a', a) self.assertEqual(start_state, q) q, a = dfa.find_transition_to_q(q2) self.assertEqual('a', a) self.assertEqual(q1, q)
def test_nfa_to_dfa_04(self): nfa = automaton.NFA({'a', 'b'}) q0 = automaton.State('0') q1 = automaton.State('1') q2 = automaton.State('2') q3 = automaton.State('3') nfa.add_state(q0) nfa.add_state(q1) nfa.add_state(q2) nfa.add_state(q3) nfa.add_transition(q0, q1, '') nfa.add_transition(q1, q2, '') nfa.add_transition(q1, q3, 'a') nfa.add_transition(q2, q1, 'a') nfa.add_transition(q3, q3, 'b') nfa.add_transition(q3, q2, 'a') nfa.add_transition(q3, q2, 'b') nfa.add_accepting_state(q2) nfa.add_start_state(q0) nfa.add_start_state(q1) dfa = nfa.to_dfa().minimize() self.assertEqual(4, len(dfa.states)) self.assertEqual(3, len(dfa.accept_states))
def test_active_lstar_10(self): """ try to let L* learn the regular language L. L is a regular language over the alphabet {a, b} where for every string in L, we have the following property, the characters at an even position should be a, the characters at an odd position can be a or b. The empty string is not accepted by the language. """ q0 = automaton.State('0') q1 = automaton.State('1') q2 = automaton.State('2') q3 = automaton.State('3') expected_dfa = automaton.DFA({'a', 'b'}, start_state=q0) expected_dfa.add_transition(q0, q1, 'a') expected_dfa.add_transition(q0, q1, 'b') expected_dfa.add_transition(q1, q2, 'b') expected_dfa.add_transition(q1, q3, 'a') expected_dfa.add_transition(q2, q2, 'a') expected_dfa.add_transition(q2, q2, 'b') expected_dfa.add_transition(q3, q1, 'a') expected_dfa.add_transition(q3, q1, 'b') expected_dfa.accept_states.update({q1, q3}) teacher = oracle.ActiveOracle(expected_dfa) lstar = algorithms.LSTAR({'a', 'b'}, teacher) dfa = lstar.learn() s_plus = set() s_minus = set() for i in self._combinations({'a', 'b'}, 8): if i == '': s_minus.add(i) continue cpy = list(i[:]) for idx in range(len(i)): if idx % 2 == 1: cpy[idx] = 'a' s_plus.add(''.join(cpy)) if all([i[q] == 'a' for q in range(1, len(i), 2)]): s_plus.add(i) else: s_minus.add(i) for s in s_plus: self.assertTrue(dfa.parse_string(s)[1]) for s in s_minus: self.assertFalse(dfa.parse_string(s)[1])
def test_rpni_08(self): """ try to let RPNI learn the regular language L. L is a regular language over the alphabet {0, 1} where each string contains an odd number of 1s """ random.seed(10012) s_plus = set() s_minus = set() for i in range(1, 15, 2): positive_example = list('1' * i + '0' * random.randint(0, 6)) negative_example = list('1' * (i - 1) + '0' * random.randint(0, 6)) random.shuffle(positive_example) random.shuffle(negative_example) s_plus.add(''.join(positive_example)) s_minus.add(''.join(negative_example)) rpni = algorithms.RPNI(s_plus, s_minus, {'0', '1'}) dfa = rpni.learn() q_lambda = automaton.State('') q1 = automaton.State('1') self.assertSetEqual({q_lambda, q1}, dfa.states) self.assertSetEqual({q1}, dfa.accept_states) self.assertSetEqual({q_lambda}, dfa.reject_states) expected_transitions = OrderedDict({ q_lambda: OrderedDict({ '0': q_lambda, '1': q1, }), automaton.State('1'): OrderedDict({ '0': q1, '1': q_lambda, }) }) self.assertSetEqual(set(map(str, expected_transitions.keys())), set(map(str, dfa._transitions.keys()))) for k in expected_transitions.keys(): for a in expected_transitions[k].keys(): self.assertEqual(expected_transitions[k][a], dfa._transitions[k][a]) for s in s_plus: self.assertTrue(dfa.parse_string(s)[1]) for s in s_minus: self.assertFalse(dfa.parse_string(s)[1])
def test_build_automaton_01(self): blue = {'b', 'aa', 'ab'} red = {'', 'a'} ot = utils.ObservationTable(blue, red, {'a', 'b'}) ot.put('', '', 0) ot.put('', 'a', 1) ot.put('a', '', 1) ot.put('a', 'a', 0) ot.put('b', '', 1) ot.put('b', 'a', 0) ot.put('aa', '', 0) ot.put('aa', 'a', 1) ot.put('ab', '', 1) ot.put('ab', 'a', 0) self.assertTrue(ot.is_closed()[0]) self.assertTrue(ot.is_consistent()) self.assertEqual((True, True), ot.is_closed_and_consistent()) gold = algorithms.Gold({'a', 'b'}, set(), {'a', 'b'}) gold._blue = blue gold._red = red dfa = gold._build_automaton(ot) self.assertSetEqual({'a', 'b'}, dfa.alphabet) self.assertTrue(2, len(dfa.states)) self.assertTrue(1, len(dfa.accept_states)) self.assertTrue(1, len(dfa.reject_states)) q1 = automaton.State('') q2 = automaton.State('a') expected_transitions = OrderedDict({ q1: OrderedDict({ 'a': q2, 'b': q2 }), q2: OrderedDict({ 'a': q1, 'b': q2 }) }) self.assertSetEqual(set(map(str, expected_transitions.keys())), set(map(str, dfa._transitions.keys()))) for k in expected_transitions.keys(): for a in expected_transitions[k].keys(): self.assertEqual(expected_transitions[k][a], dfa._transitions[k][a])
def _build_automaton(self, ot: utils.ObservationTable) -> automaton.DFA: """ Builds an automaton from the observation table. :param ot: The data to build the dfa from. :type ot: ObservationTable :return: The dfa built from the observation table. :rtype: DFA """ self._logger.info('Building DFA from the table.') dfa = automaton.DFA(self._alphabet) for u in self._red: for v in ot.ot.keys(): if u == v: continue if len(v) < len(u) and ot.get_row(v) != ot.get_row(u): dfa.states.add(automaton.State(u)) for u in dfa.states: if ot.entry_exists(u.name, ''): if ot.get(u.name, '') == 1: dfa.accept_states.add(u) elif ot.get(u.name, '') == 0: dfa.reject_states.add(u) for a in self._alphabet: for w in dfa.states: if ot.get_row(u.name + a) == ot.get_row(w.name): dfa.add_transition(u, w, a) return dfa.rename_states()
def test_renamed_and_eq_01(self): alphabet = {'0', '1'} qa = automaton.State('a') qb = automaton.State('b') qc = automaton.State('c') qd = automaton.State('d') qe = automaton.State('e') qf = automaton.State('f') dfa = automaton.DFA(alphabet, qa) dfa.add_transition(qa, qb, '0') dfa.add_transition(qa, qc, '1') dfa.add_transition(qb, qa, '0') dfa.add_transition(qb, qd, '1') dfa.add_transition(qc, qe, '0') dfa.add_transition(qc, qf, '1') dfa.add_transition(qd, qe, '0') dfa.add_transition(qd, qf, '1') dfa.add_transition(qe, qe, '0') dfa.add_transition(qe, qf, '1') dfa.add_transition(qf, qf, '0') dfa.add_transition(qf, qf, '1') dfa.accept_states.update({qc, qd, qe}) dfa = dfa.minimize() q0 = automaton.State('0') q1 = automaton.State('1') q2 = automaton.State('2') expected_dfa = automaton.DFA(alphabet, q0) expected_dfa.add_transition(q0, q1, '1') expected_dfa.add_transition(q0, q0, '0') expected_dfa.add_transition(q1, q2, '1') expected_dfa.add_transition(q1, q1, '0') expected_dfa.add_transition(q2, q2, '1') expected_dfa.add_transition(q2, q2, '0') expected_dfa.accept_states.add(q1) self.assertEqual(expected_dfa, dfa)
def test_nfa_03(self): nfa = automaton.NFA({'a', 'b'}) q1 = automaton.State('q1') q2 = automaton.State('q2') q3 = automaton.State('q3') nfa.add_state(q1) nfa.add_state(q2) nfa.add_state(q3) nfa.add_transition(q1, q2, 'b') nfa.add_transition(q1, q3, '') nfa.add_transition(q2, q2, 'a') nfa.add_transition(q2, q3, 'a') nfa.add_transition(q2, q3, 'b') nfa.add_transition(q3, q1, 'a') nfa.add_accepting_state(q1) nfa.add_start_state(q1) state, accepted = nfa.parse_string('') self.assertTrue(accepted) self.assertEqual(state.name, 'q1') state, accepted = nfa.parse_string('a') self.assertTrue(accepted) self.assertEqual(state.name, 'q1') state, accepted = nfa.parse_string('baba') self.assertTrue(accepted) self.assertEqual(state.name, 'q1') state, accepted = nfa.parse_string('baa') self.assertTrue(accepted) self.assertEqual(state.name, 'q1') _, accepted = nfa.parse_string('b') self.assertFalse(accepted) _, accepted = nfa.parse_string('bb') self.assertFalse(accepted) _, accepted = nfa.parse_string('babba') self.assertFalse(accepted)
def test_active_lstar_11(self): """ try to let L* learn the regular language L. L is a regular language over the alphabet {a, b} where for every string in L contains exactly two a's. """ q0 = automaton.State('0') q1 = automaton.State('1') q2 = automaton.State('2') q3 = automaton.State('3') expected_dfa = automaton.DFA({'a', 'b'}, start_state=q0) expected_dfa.add_transition(q0, q0, 'b') expected_dfa.add_transition(q0, q1, 'a') expected_dfa.add_transition(q1, q1, 'b') expected_dfa.add_transition(q1, q2, 'a') expected_dfa.add_transition(q2, q2, 'b') expected_dfa.add_transition(q2, q3, 'a') expected_dfa.add_transition(q3, q3, 'a') expected_dfa.add_transition(q3, q3, 'b') expected_dfa.accept_states.add(q2) teacher = oracle.ActiveOracle(expected_dfa) lstar = algorithms.LSTAR({'a', 'b'}, teacher) dfa = lstar.learn() s_plus = set() s_minus = set() for i in self._combinations({'a', 'b'}, 11): if i.count('a') == 2: s_plus.add(i) else: s_minus.add(i) for s in s_minus: self.assertFalse(dfa.parse_string(s)[1]) self.assertEqual(expected_dfa, dfa)
def test_active_lstar_07(self): """ try to let L* learn the regular language A. A is a regular language over the alphabet {0, 1} where each string contains 101 as a substring. """ q1 = automaton.State('1') q2 = automaton.State('2') q3 = automaton.State('3') q4 = automaton.State('4') expected_dfa = automaton.DFA({'0', '1'}, start_state=q1) expected_dfa.add_transition(q1, q1, '0') expected_dfa.add_transition(q1, q2, '1') expected_dfa.add_transition(q2, q2, '1') expected_dfa.add_transition(q2, q3, '0') expected_dfa.add_transition(q3, q1, '0') expected_dfa.add_transition(q3, q4, '1') expected_dfa.add_transition(q4, q4, '0') expected_dfa.add_transition(q4, q4, '1') expected_dfa.accept_states.add(q4) teacher = oracle.ActiveOracle(expected_dfa) lstar = algorithms.LSTAR({'0', '1'}, teacher) dfa = lstar.learn() s_plus = set() s_minus = {''} for i in self._combinations({'0', '1'}, 10): if len(i) < 3: continue if '101' in i: s_plus.add(i) else: s_minus.add(i) for s in s_plus: self.assertTrue(dfa.parse_string(s)[1]) for s in s_minus: self.assertFalse(dfa.parse_string(s)[1])
def test_nfa_02(self): nfa = automaton.NFA({'0', '1'}) q1 = automaton.State('q1') q2 = automaton.State('q2') q3 = automaton.State('q3') q4 = automaton.State('q4') nfa.add_state(q1) nfa.add_state(q2) nfa.add_state(q3) nfa.add_state(q4) nfa.add_transition(q1, q1, '0') nfa.add_transition(q1, q1, '1') nfa.add_transition(q1, q2, '1') nfa.add_transition(q2, q3, '0') nfa.add_transition(q2, q3, '1') nfa.add_transition(q3, q4, '0') nfa.add_transition(q3, q4, '1') nfa.add_accepting_state(q4) nfa.add_start_state(q1) s_plus = set() s_minus = set() for comb in self._combinations({'0', '1'}, 8): if len(comb) < 3: s_minus.add(comb) elif comb[-3] == '1': s_plus.add(comb) else: s_minus.add(comb) for s in s_plus: state, accepted = nfa.parse_string(s) self.assertTrue(accepted) self.assertEqual(state.name, 'q4') for s in s_minus: _, accepted = nfa.parse_string(s) self.assertFalse(accepted)
def test_active_lstar_04(self): q0 = automaton.State('0') q1 = automaton.State('1') expected_dfa = automaton.DFA({'a', 'b'}, start_state=q0) expected_dfa.add_transition(q0, q1, 'a') expected_dfa.add_transition(q0, q1, 'b') expected_dfa.add_transition(q1, q1, 'a') expected_dfa.add_transition(q1, q1, 'b') expected_dfa.accept_states.add(q1) teacher = oracle.ActiveOracle(expected_dfa) lstar = algorithms.LSTAR({'a', 'b'}, teacher) dfa = lstar.learn() self.assertEqual(2, len(dfa.states)) self.assertEqual(1, len(dfa.accept_states))
def test_minimize_01(self): alphabet = {'0', '1'} q0 = automaton.State('0') q1 = automaton.State('1') q2 = automaton.State('2') q3 = automaton.State('3') q4 = automaton.State('4') q5 = automaton.State('5') dfa = automaton.DFA(alphabet, q0) dfa.add_transition(q0, q3, '0') dfa.add_transition(q0, q1, '1') dfa.add_transition(q1, q2, '0') dfa.add_transition(q1, q5, '1') dfa.add_transition(q2, q2, '0') dfa.add_transition(q2, q5, '1') dfa.add_transition(q3, q4, '1') dfa.add_transition(q3, q0, '0') dfa.add_transition(q4, q2, '0') dfa.add_transition(q4, q5, '1') dfa.add_transition(q5, q5, '0') dfa.add_transition(q5, q5, '1') dfa.accept_states.update({q1, q2, q4}) minimized_dfa = dfa.minimize() self.assertEqual(3, len(minimized_dfa.states)) self.assertEqual(1, len(minimized_dfa.accept_states))
def test_rpni_09(self): """ try to let RPNI learn the regular language L. L is a regular language over the alphabet {0, 1} where each string contains an odd number of 1s. This is for the same regular language as the test above, but with different example strings. """ random.seed(10012) s_plus = set() s_minus = set() for i in range(1, 15, 2): s_plus.add('1' * i + '0' * random.randint(0, 6)) s_minus.add('1' * (i - 1) + '0' * random.randint(0, 6)) rpni = algorithms.RPNI(s_plus, s_minus, {'0', '1'}) dfa = rpni.learn() self.assertEqual(10, len(dfa.states)) self.assertSetEqual( {automaton.State(''), automaton.State('111111111')}, dfa.accept_states) self.assertSetEqual( { automaton.State('1'), automaton.State('11'), automaton.State('111111'), automaton.State('1111') }, dfa.reject_states) for s in s_plus: self.assertTrue(dfa.parse_string(s)[1]) for s in s_minus: self.assertFalse(dfa.parse_string(s)[1])
def test_active_nlstar_01(self): q0 = automaton.State('0') q1 = automaton.State('1') q2 = automaton.State('2') q3 = automaton.State('3') q4 = automaton.State('4') expected_dfa = automaton.DFA({'a', 'b'}, start_state=q0) expected_dfa.add_transition(q0, q1, 'a') expected_dfa.add_transition(q0, q2, 'b') expected_dfa.add_transition(q1, q3, 'a') expected_dfa.add_transition(q1, q4, 'b') expected_dfa.add_transition(q2, q3, 'a') expected_dfa.add_transition(q2, q3, 'b') expected_dfa.add_transition(q4, q2, 'a') expected_dfa.add_transition(q4, q3, 'b') expected_dfa.add_transition(q3, q3, 'a') expected_dfa.add_transition(q3, q3, 'b') expected_dfa.accept_states.update({q0, q1, q2, q4}) teacher = oracle.ActiveOracle(expected_dfa) nlstar = algorithms.NLSTAR({'a', 'b'}, teacher) nfa = nlstar.learn() self.assertTrue(nfa.parse_string('')[1]) self.assertTrue(nfa.parse_string('a')[1]) self.assertTrue(nfa.parse_string('ab')[1]) self.assertTrue(nfa.parse_string('aba')[1]) self.assertFalse(nfa.parse_string('aa')[1]) self.assertFalse(nfa.parse_string('abb')[1]) self.assertFalse(nfa.parse_string('ba')[1]) self.assertFalse(nfa.parse_string('bb')[1])
def learn(self) -> automaton.DFA: """ Learns the grammar from the sets of positive and negative example strings. This method returns a DFA that is consistent with the sample. :return: DFA :rtype: Automaton """ self._logger.info('Start learning with alphabet = {}\n' 'positive samples = {}\n' 'negative samples = {}'.format( self._alphabet, self._pos_examples, self._neg_examples)) self._logger.info('Building PTA') dfa = automaton.build_pta(self._pos_examples) pref_set = utils.prefix_set(self._pos_examples) self._blue = { automaton.State(i) for i in self._alphabet.intersection(pref_set) } while len(self._blue) != 0: qb = _choose(self._blue) self._blue.remove(qb) found = False for qr in sorted(self._red, key=functools.cmp_to_key(_cmp)): if self._compatible(self._merge(dfa.copy(), qr, qb)): dfa = self._merge(dfa, qr, qb) new_blue_states = set() for q in self._red: for a in self._alphabet: if dfa.transition_exists(q, a) and \ dfa.transition(q, a) not in self._red: new_blue_states.add(dfa.transition(q, a)) self._blue.update(new_blue_states) found = True if not found: dfa = self._promote(qb, dfa) for s in self._neg_examples: q, accepted = dfa.parse_string(s) if not accepted: dfa.reject_states.add(q) return dfa.remove_dead_states()
def test_dfa_01(self): dfa = automaton.DFA({'a', 'b'}) self.assertTrue(automaton.State('') in dfa.states) dfa.add_transition(automaton.State(''), automaton.State('a'), 'a') self.assertTrue(dfa.transition_exists(automaton.State(''), 'a')) self.assertEqual(automaton.State('a'), dfa.transition(automaton.State(''), 'a')) try: dfa.add_transition(automaton.State(''), automaton.State('a'), 'c') self.fail('Automaton should throw ValueError when trying to add' 'transition with letter that is not in the alphabet!') except ValueError: self.assertTrue(True)
def test_active_lstar_03(self): """ Try to let L* learn Kleene plus. The alphabet is sigma = {a} and the language accepts every string with 1 or more a's. """ q0 = automaton.State('0') q1 = automaton.State('1') expected_dfa = automaton.DFA({'a'}, start_state=q0) expected_dfa.add_transition(q0, q1, 'a') expected_dfa.add_transition(q1, q1, 'a') expected_dfa.accept_states.add(q1) teacher = oracle.ActiveOracle(expected_dfa) lstar = algorithms.LSTAR({'a'}, teacher) dfa = lstar.learn() self.assertEqual(2, len(dfa.states)) self.assertEqual(1, len(dfa.accept_states))
def test_active_nlstar_10(self): """ try to let NL* learn the regular language L. L is a regular language over the alphabet {a, b} where for every string in L, we have the following property, the characters at an even position should be a, the characters at an odd position can be a or b. The empty string is not accepted by the language. """ q0 = automaton.State('0') q1 = automaton.State('1') q2 = automaton.State('2') q3 = automaton.State('3') expected_dfa = automaton.DFA({'a', 'b'}, start_state=q0) expected_dfa.add_transition(q0, q1, 'a') expected_dfa.add_transition(q0, q1, 'b') expected_dfa.add_transition(q1, q2, 'b') expected_dfa.add_transition(q1, q3, 'a') expected_dfa.add_transition(q2, q2, 'a') expected_dfa.add_transition(q2, q2, 'b') expected_dfa.add_transition(q3, q1, 'a') expected_dfa.add_transition(q3, q1, 'b') expected_dfa.accept_states.update({q1, q3}) teacher = oracle.ActiveOracle(expected_dfa) nlstar = algorithms.NLSTAR({'a', 'b'}, teacher) nfa = nlstar.learn() dfa = nfa.to_dfa() self.assertEqual(expected_dfa.rename_states(), dfa.rename_states())