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_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 add_columns_to_row(self, row: Row): """ Adds all of the suffixes that are currently in the observation table to the given row. :param row: Row to whom the suffixes should be added for. :type row: Row """ for suffix in self.suffixes: mq = self._oracle.membership_query(row.prefix + suffix) row.columns[suffix] = mq
def initialize(self): """ Initializes the observation table. The prefix-closed set is initialized with the empty string and all of the symbols in the alphabet of the regular language we are trying to infer. The suffix-closed set is initialized with the empty string. """ row = Row('') self.rows.add(row) self.upper_rows.add(row) self.prefix_to_row[row.prefix] = row for symbol in self._alphabet: row = Row(symbol) self.rows.add(row) self.lower_rows.add(row) self.prefix_to_row[row.prefix] = row self.add_suffix('') self.update_meta_data()
def is_closed(self) -> Tuple[bool, Row]: """ An observation table is closed if and only if any prime row of the lower part is a prime row of the upper part. :return: Whether the table is closed, along with the unclosed row if there is one. :rtype: Tuple[bool, Row] """ for row in self.lower_rows: covered = [r_prime for r_prime in self.upper_primes if r_prime.covered_by(row)] if len(covered) == 0 or \ not Row.join(covered).columns_are_equal(row): return False, row return True, None
def _close_table(self, unclosed_row): """ Attempts to close the observation table by adding a new row to the table. """ self._logger.info('Attempting to close the table by adding a new row.') self._ot.upper_rows.add(unclosed_row) self._ot.lower_rows.remove(unclosed_row) self._ot.upper_primes.add(unclosed_row) for symbol in self._alphabet: new_row = Row(unclosed_row.prefix + symbol) self._ot.rows.add(new_row) self._ot.lower_rows.add(new_row) self._ot.prefix_to_row[new_row.prefix] = new_row self._ot.add_columns_to_row(new_row) self._ot.update_meta_data()
def test_ot_01(self): ot = ObservationTable({'a', 'b'}, oracle.PassiveOracle(set(), set())) row1 = Row('') row2 = Row('a') row3 = Row('ab') row4 = Row('b') row5 = Row('aa') row6 = Row('abb') row7 = Row('aba') ot.suffixes = {'', 'aaa', 'aa', 'a'} ot.rows = {row1, row2, row3, row4, row5, row6, row7} ot.upper_rows = {row1, row2, row3} ot.lower_rows = {row4, row5, row6, row7} 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 = {'': 0, 'aaa': 1, 'aa': 0, 'a': 0} row5.columns = {'': 0, 'aaa': 1, 'aa': 1, 'a': 1} row6.columns = {'': 1, 'aaa': 1, 'aa': 0, 'a': 0} row7.columns = {'': 1, 'aaa': 1, 'aa': 1, 'a': 0} ot.update_meta_data() composed_rows = ot.primes.symmetric_difference(ot.rows) self.assertEqual(5, len(ot.primes)) self.assertEqual(2, len(composed_rows)) for i in ['', 'a', 'ab', 'b', 'abb']: self.assertTrue(i in map(lambda r: r.prefix, ot.primes)) for i in ['aa', 'aba']: self.assertTrue(i in map(lambda r: r.prefix, composed_rows))
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])