def test_closed_and_consistent_02(self): ot = ObservationTable({'a', 'b'}, oracle.PassiveOracle(set(), set())) row1 = Row('') row2 = Row('b') row3 = Row('a') ot.suffixes = {'', 'aaa', 'aa', 'a'} ot.rows = {row1, row2, row3} ot.upper_rows = {row1} ot.lower_rows = {row2, row3} row1.columns = {'': 0, 'aaa': 1, 'aa': 0, 'a': 0} row2.columns = {'': 0, 'aaa': 1, 'aa': 0, 'a': 0} row3.columns = {'': 0, 'aaa': 1, 'aa': 1, 'a': 0} ot.update_meta_data() self.assertEqual(2, len(ot.primes)) self.assertEqual(1, len(ot.rows.symmetric_difference(ot.primes))) nlstar = algorithms.NLSTAR({'a', 'b'}, oracle.PassiveOracle(set(), set())) nlstar._ot = ot closed_info, consistency_info = ot.is_closed_and_consistent() is_closed, unclosed_rows = closed_info is_consistent, _, _ = consistency_info self.assertFalse(is_closed) self.assertTrue(is_consistent) nlstar._close_table(unclosed_rows) self.assertEqual(5, len(nlstar._ot.rows))
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_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_09(self): """ try to let NL* 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) nlstar = algorithms.NLSTAR({'a', 'b', 'c'}, teacher) nfa = nlstar.learn() dfa = nfa.to_dfa() self.assertEqual(expected_dfa, dfa)
def test_passive_nlstar_10(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 even number of 0's and an even number of 1's. """ random.seed(10012) s_plus = set() s_minus = set() for i in self._combinations({'0', '1'}, 13): if i.count('0') % 2 == 0 and i.count('1') % 2 == 0: s_plus.add(i) else: s_minus.add(i) teacher = oracle.PassiveOracle(s_plus, s_minus) nlstar = algorithms.NLSTAR({'0', '1'}, teacher) nfa = nlstar.learn() for s in s_plus: self.assertTrue(nfa.parse_string(s)[1]) for s in s_minus: self.assertFalse(nfa.parse_string(s)[1])
def test_active_nlstar_08(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 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) nlstar = algorithms.NLSTAR({'a', 'b'}, teacher) nfa = nlstar.learn() dfa = nfa.to_dfa() self.assertTrue(expected_dfa, dfa)
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_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_closed_and_consistent_01(self): ot = ObservationTable({'a', 'b'}, oracle.PassiveOracle(set(), set())) row1 = Row('') row2 = Row('b') row3 = Row('a') ot.suffixes = {'', 'aaa', 'aa', 'a'} ot.rows = [row1, row2, row3] ot.upper_rows = [row1] ot.lower_rows = [row2, row3] row1.columns = {'': 0, 'aaa': 1, 'aa': 0, 'a': 0} row2.columns = {'': 0, 'aaa': 1, 'aa': 0, 'a': 0} row3.columns = {'': 0, 'aaa': 1, 'aa': 1, 'a': 0} ot.update_meta_data() self.assertEqual(2, len(ot.primes)) nlstar = algorithms.NLSTAR({'a', 'b'}, oracle.PassiveOracle(set(), set())) nlstar._ot = ot self.assertFalse(ot.is_closed()[0]) self.assertTrue(ot.is_consistent()[0])
def test_passive_nlstar_01(self): s_plus = {'a' * i for i in range(25)} teacher = oracle.PassiveOracle(s_plus, set()) nlstar = algorithms.NLSTAR({'a'}, teacher) nfa = nlstar.learn() self.assertEqual(1, len(nfa._states)) self.assertEqual(1, len(nfa._accept_states)) self.assertTrue(nfa.parse_string('a' * 1000)[1])
def test_passive_nlstar_02(self): """ Try to let NL* learn Kleene plus. The alphabet is sigma = {a} and the language accepts every string with 1 or more a's. """ s_plus = {'a', 'aa', 'aaa', 'aaaa', 'aaaaaaaa'} s_minus = {''} teacher = oracle.PassiveOracle(s_plus, s_minus) nlstar = algorithms.NLSTAR({'a'}, teacher) nfa = nlstar.learn() self.assertEqual(2, len(nfa._states)) self.assertEqual(1, len(nfa._accept_states))
def test_active_nlstar_02(self): q0 = automaton.State('0') expected_dfa = automaton.DFA({'a'}, start_state=q0) expected_dfa.add_transition(q0, q0, 'a') expected_dfa.accept_states.add(q0) teacher = oracle.ActiveOracle(expected_dfa) nlstar = algorithms.NLSTAR({'a'}, teacher) nfa = nlstar.learn() self.assertEqual(1, len(nfa._states)) self.assertEqual(1, len(nfa._accept_states)) self.assertTrue(nfa.parse_string('a' * 1000)[1])
def test_passive_nlstar_03(self): s_plus = set() s_minus = set() for i in self._combinations({'a', 'b'}, 4): if i == '': s_minus.add(i) else: s_plus.add(i) teacher = oracle.PassiveOracle(s_plus, s_minus) nlstar = algorithms.NLSTAR({'a', 'b'}, teacher) nfa = nlstar.learn() dfa = nfa.to_dfa() self.assertEqual(2, len(dfa.states)) self.assertEqual(1, len(dfa.accept_states)) for s in s_plus: self.assertTrue(nfa.parse_string(s)[1]) for s in s_minus: self.assertFalse(nfa.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 test_active_nlstar_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) nlstar = algorithms.NLSTAR({'a', 'b'}, teacher) nfa = nlstar.learn() dfa = nfa.to_dfa() self.assertEqual(2, len(dfa.states)) self.assertEqual(1, len(dfa.accept_states))
def test_passive_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. """ 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) teacher = oracle.PassiveOracle(s_plus, s_minus) nlstar = algorithms.NLSTAR({'a', 'b'}, teacher) nfa = nlstar.learn() for s in s_plus: self.assertTrue(nfa.parse_string(s)[1]) for s in s_minus: self.assertFalse(nfa.parse_string(s)[1])
def test_passive_nlstar_09(self): """ try to let NL* learn the regular language L. L is a regular language over the alphabet {a, b} where every string in L is an odd length. """ s_plus = set() s_minus = set() for i in self._combinations({'a', 'b'}, 6): if len(i) % 2 == 1: s_plus.add(i) else: s_minus.add(i) teacher = oracle.PassiveOracle(s_plus, s_minus) nlstar = algorithms.NLSTAR({'a', 'b'}, teacher) nfa = nlstar.learn() for s in s_plus: self.assertTrue(nfa.parse_string(s)[1]) for s in s_minus: self.assertFalse(nfa.parse_string(s)[1])
def test_passive_nlstar_05(self): """ try to let NL* learn the regular language A. A is a regular language over the alphabet {a, b, c} where each string contains an even number of a's """ random.seed(10012) s_plus = set() s_minus = set() for i in self._combinations({'a', 'b', 'c'}, 6): if i == '': continue if i.count('a') % 2 == 0: s_plus.add(i) else: s_minus.add(i) teacher = oracle.PassiveOracle(s_plus, s_minus) nlstar = algorithms.NLSTAR({'a', 'b', 'c'}, teacher) nfa = nlstar.learn() for s in s_minus: self.assertFalse(nfa.parse_string(s)[1])
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())
def test_passive_nlstar_04(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. """ s_plus = set() s_minus = set() for i in range(1, 21, 2): s_plus.add('a' * i) s_minus.add('a' * (i - 1)) teacher = oracle.PassiveOracle(s_plus, s_minus) nlstar = algorithms.NLSTAR({'a'}, teacher) nfa = nlstar.learn() self.assertEqual(2, len(nfa._states)) self.assertEqual(1, len(nfa._accept_states)) for s in s_plus: self.assertTrue(nfa.parse_string(s)[1]) for s in s_minus: self.assertFalse(nfa.parse_string(s)[1])
def test_active_nlstar_03(self): """ Try to let NL* 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) nlstar = algorithms.NLSTAR({'a'}, teacher) nfa = nlstar.learn() self.assertEqual(2, len(nfa._states)) self.assertEqual(1, len(nfa._accept_states))
def __init__(self, alphabet: Set[str], pos_examples: Set[str] = None, neg_examples: Set[str] = None, oracle: Oracle = None, algorithm: str = 'rpni'): """ :param alphabet: Alphabet of the target language we are trying to learn. :type alphabet: Set[str] :param pos_examples: Set of positive example strings from the target language. :type pos_examples: Set[str] :param neg_examples: Set of negative example strings, i.e. strings that do not belong in the target language. :type neg_examples: Set[str] :param oracle: Minimally adequate teacher (MAT) :type oracle: Oracle :param algorithm: The algorithm to use when attempting to learn the grammar from the example strings. The options are: gold rpni lstar nlstar :type algorithm: str """ if not isinstance(alphabet, set) or len(alphabet) == 0: raise ValueError( 'The alphabet has to be a set with at least one element') self._alphabet = alphabet self._learners = { 'gold': lambda: algorithms.Gold(pos_examples, neg_examples, self._alphabet ).learn(), 'rpni': lambda: algorithms.RPNI(pos_examples, neg_examples, self._alphabet) .learn(), 'lstar': lambda: algorithms.LSTAR(self._alphabet, oracle).learn(), 'nlstar': lambda: algorithms.NLSTAR(self._alphabet, oracle).learn() } if algorithm not in self._learners: raise ValueError('Algorithm \'{}\' unknown, the following ' 'algorithms are available:\n{}'.format( algorithms, '\n'.join(self._learners.keys()))) if algorithm in ['rpni', 'gold']: if not isinstance(pos_examples, set): raise ValueError('pos_examples should be a set') if not isinstance(neg_examples, set): raise ValueError('neg_examples should be a set') if len(pos_examples.intersection(neg_examples)) != 0: raise ValueError( 'The sets of positive and negative example ' 'strings should not contain the same string(s)') if pos_examples is None or neg_examples is None: raise ValueError( 'pos_examples and neg_examples can not be None ' 'for algorithm \'{}\''.format(algorithm)) self._alphabet = utils.determine_alphabet( pos_examples.union(neg_examples)) elif algorithm in ['lstar', 'nlstar']: if oracle is None: raise ValueError( 'oracle can not be None for algorithm \'{}\''.format( algorithm)) self._algorithm = algorithm
def test_active_nlstar_12(self): q0 = automaton.State('0') q1 = automaton.State('1') q2 = automaton.State('2') q3 = automaton.State('3') q4 = automaton.State('4') q5 = automaton.State('5') q6 = automaton.State('6') q7 = automaton.State('7') expected_dfa = automaton.DFA({'a', '1', '#'}, start_state=q0) expected_dfa.add_transition(q0, q1, '#') expected_dfa.add_transition(q0, q2, '1') expected_dfa.add_transition(q0, q3, 'a') expected_dfa.add_transition(q1, q1, '#') expected_dfa.add_transition(q1, q4, '1') expected_dfa.add_transition(q1, q5, 'a') expected_dfa.add_transition(q2, q2, '1') expected_dfa.add_transition(q2, q4, '#') expected_dfa.add_transition(q2, q6, 'a') expected_dfa.add_transition(q3, q3, 'a') expected_dfa.add_transition(q3, q5, '#') expected_dfa.add_transition(q3, q6, '1') expected_dfa.add_transition(q4, q4, '1') expected_dfa.add_transition(q4, q4, '#') expected_dfa.add_transition(q4, q7, 'a') expected_dfa.add_transition(q5, q5, '#') expected_dfa.add_transition(q5, q5, 'a') expected_dfa.add_transition(q5, q7, '1') expected_dfa.add_transition(q6, q6, '1') expected_dfa.add_transition(q6, q6, 'a') expected_dfa.add_transition(q6, q7, '#') expected_dfa.add_transition(q7, q7, '1') expected_dfa.add_transition(q7, q7, 'a') expected_dfa.add_transition(q7, q7, '#') expected_dfa.accept_states.add(q7) teacher = oracle.ActiveOracle(expected_dfa) nlstar = algorithms.NLSTAR({'#', '1', 'a'}, teacher) nfa = nlstar.learn() dfa = nfa.to_dfa() self.assertEqual(8, len(dfa.states)) self.assertEqual(1, len(dfa.accept_states)) self.assertTrue(dfa.parse_string('#1a')[1]) self.assertTrue(dfa.parse_string('a#1')[1]) self.assertFalse(dfa.parse_string('#1')[1]) self.assertFalse(dfa.parse_string('a')[1]) self.assertEqual(expected_dfa, dfa)
def test_build_hypothesis_01(self): ot = ObservationTable({'a', 'b'}, oracle.PassiveOracle(set(), set())) row1 = Row('') row2 = Row('a') row3 = Row('ab') row4 = Row('abb') row5 = Row('b') row6 = Row('aa') row7 = Row('aba') row8 = Row('abbb') row9 = Row('abba') ot.suffixes = {'', 'aaa', 'aa', 'a'} ot.rows = {row1, row2, row3, row4, row5, row6, row7, row8, row9} ot.upper_rows = {row1, row2, row3, row4} ot.lower_rows = {row5, row6, row7, row8, row9} row1.columns = {'': 0, 'aaa': 1, 'aa': 0, 'a': 0} row2.columns = {'': 0, 'aaa': 1, 'aa': 1, 'a': 0} row3.columns = {'': 0, 'aaa': 1, 'aa': 0, 'a': 1} row4.columns = {'': 1, 'aaa': 1, 'aa': 0, 'a': 0} row5.columns = {'': 0, 'aaa': 1, 'aa': 0, 'a': 0} row6.columns = {'': 0, 'aaa': 1, 'aa': 1, 'a': 1} row7.columns = {'': 1, 'aaa': 1, 'aa': 1, 'a': 0} row8.columns = {'': 0, 'aaa': 1, 'aa': 0, 'a': 0} row9.columns = {'': 0, 'aaa': 1, 'aa': 1, 'a': 0} ot.prefix_to_row = {r.prefix: r for r in ot.rows} ot.update_meta_data() nlstar = algorithms.NLSTAR({'a', 'b'}, oracle.PassiveOracle(set(), set())) nlstar._ot = ot nfa = nlstar._build_hypothesis() self.assertEqual(4, len(nfa._states)) self.assertEqual(1, len(nfa._accept_states)) s_plus = set() s_minus = set() so_long = [] for i in self._combinations({'a', 'b'}, 6): so_long.append(i) for i in self._combinations({'a', 'b'}, 2): if len(i) != 2: continue for pre in so_long: s_plus.add('{}a{}'.format(pre, i)) s_minus.add('{}b{}'.format(pre, i)) for s in s_plus: self.assertTrue(nfa.parse_string(s)[1]) for s in s_minus: self.assertFalse(nfa.parse_string(s)[1])