Exemple #1
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))
Exemple #2
0
    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)
Exemple #3
0
    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())
Exemple #4
0
    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)
Exemple #5
0
    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])
Exemple #6
0
    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)
Exemple #7
0
    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())
Exemple #8
0
    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())
Exemple #9
0
    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])
Exemple #10
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])
Exemple #11
0
    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))
Exemple #12
0
    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])
Exemple #13
0
    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])
Exemple #14
0
    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])
Exemple #15
0
    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))
Exemple #16
0
    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])
Exemple #17
0
    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])
Exemple #18
0
    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])
Exemple #19
0
    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())
Exemple #20
0
    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])
Exemple #21
0
    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))
Exemple #22
0
    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
Exemple #23
0
    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)
Exemple #24
0
    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])