def to_dfsm(self): transitions = {} accepting = set() initial = State() closure = self._get_epsilon_closure(self.start) if closure & self.accepting: accepting.add(initial) key = tuple(closure) supersets = { key: initial } stack = [key] while stack: current = stack.pop() for symbol in self.alphabet: superstate = self._construct_superset(current, symbol) if not superstate: continue if superstate not in supersets: stack.append(superstate) try: state = supersets[superstate] except KeyError: state = State() supersets[superstate] = state transitions[(supersets[current], symbol)] = state if set(superstate) & self.accepting: accepting.add(state) return DFSM(alphabet=self.alphabet, states=frozenset(supersets.values()), transitions=util.freeze_map(transitions), initial=initial, accepting=accepting)
def atom_matcher(cls, symbol): start = State() accept = State() transitions = { (start, symbol): {accept} } return cls(states={start, accept}, alphabet={symbol}, transitions=util.freeze_map(transitions), initial=start, accepting={accept})
def _empty_machine(self): state = State() return self.__class__(states={state}, alphabet=self.__alphabet, transitions=FrozenDict({}), accepting=set(), initial=state)
def union(self, other): a = self.to_normal_form() b = other.to_normal_form() transitions = {**a.transitions, **b.transitions} a_accept = next(iter(a.accepting)) b_accept = next(iter(b.accepting)) start = State() accept = State() transitions[(start, constants.EPSILON)] = {a.start, b.start} self._update_state(transitions, (a_accept, constants.EPSILON), {accept}) self._update_state(transitions, (b_accept, constants.EPSILON), {accept}) return self.__class__(states=a.states | b.states | {start, accept}, alphabet=a.alphabet | b.alphabet, transitions=util.freeze_map(transitions), initial=start, accepting={accept})
def to_normal_form(self): transitions = self.transitions.dictionary.copy() prev = list(self._get_all_prev_states(self.start)) if len(prev) > 0: start = State() transitions[(start, constants.EPSILON)] = {self.start} else: start = self.start if not self._accepting_states_in_normal_form(): accept = State() for state in self.accepting: self._update_state(transitions, (state, constants.EPSILON), {accept}) else: accept = next(iter(self.accepting)) return self.__class__(states=self.states | {start, accept}, alphabet=self.alphabet, transitions=util.freeze_map(transitions), initial=start, accepting={accept})
def kleene_star(self): state = State() x = self.to_normal_form() accept = next(iter(x.accepting)) transitions = x.transitions.dictionary.copy() transitions[(state, constants.EPSILON)] = {x.start} self._update_state(transitions, (accept, constants.EPSILON), {state}) return self.__class__(states=x.states | {state}, alphabet=x.alphabet, transitions=util.freeze_map(transitions), initial=state, accepting={state}).to_normal_form()
def make_total(self): if self.is_total(): return self trash_state = State() transitions = self.transitions.dictionary.copy() for state in self.states: for symbol in self.alphabet: if (state, symbol) not in self.transitions: transitions[(state, symbol)] = {trash_state} for symbol in self.alphabet: transitions[(trash_state, symbol)] = {trash_state} return self.__class__(alphabet=self.alphabet, states=self.states | {trash_state}, initial=self.start, accepting=self.accepting, transitions=util.freeze_map(transitions))
def setUp(self): self.s1 = State('state1', 0) self.s2 = State('state2', 0) self.s3 = State('state3', 1) self.s1.add_function(self.s2, 1) self.s1.add_function(self.s1, 0) self.s2.add_function(self.s3, 1) self.s2.add_function(self.s2, 0) self.s3.add_function(self.s1, 1) self.s3.add_function(self.s3, 0)
class TestState(unittest.TestCase): def setUp(self): self.s1 = State('state1', 0) self.s2 = State('state2', 0) self.s3 = State('state3', 1) self.s1.add_function(self.s2, 1) self.s1.add_function(self.s1, 0) self.s2.add_function(self.s3, 1) self.s2.add_function(self.s2, 0) self.s3.add_function(self.s1, 1) self.s3.add_function(self.s3, 0) def test_reach(self): self.assertEqual(self.s1.direct_reach, {self.s1, self.s2}) self.assertEqual(self.s2.direct_reach, {self.s2, self.s3}) self.assertEqual(self.s3.direct_reach, {self.s1, self.s3}) def test_lt(self): self.assertTrue(self.s1 < self.s2) self.assertTrue(self.s2 < self.s3) self.assertTrue(self.s1 < 1) def test_eq(self): self.assertFalse(self.s1 == self.s2) self.assertFalse(self.s2 == self.s3) self.assertFalse(self.s1 == 1) self.assertTrue(self.s1 == self.s1) s2 = self.s1 self.assertTrue(self.s1 == s2) def test_forward(self): self.assertEqual(self.s1.clean_forward(0), self.s1) self.assertEqual(self.s1.clean_forward(1), self.s2) self.s1.add_function(self.s3, 0) self.assertEqual(self.s1.forward(0), {self.s1, self.s3}) self.assertEqual(self.s1.clean_forward(0), {self.s1, self.s3}) def test_indirect_reach(self): self.assertEqual(self.s1.indirect_reach, {self.s1, self.s2, self.s3}) def test_accepted(self): self.assertTrue(self.s3.accepted) self.assertFalse(self.s1.accepted) def test_contains(self): self.assertTrue(1 in self.s1) self.assertFalse(12 in self.s1)
k = compile_regex('a|b') assert not k.run(''), k.dump() assert k.run('a'), k.dump() assert k.run('b'), k.dump() assert not k.run('ba'), k.dump() assert not k.run('ab'), k.dump() assert not k.run('aa'), k.dump() assert not k.run('bb'), k.dump() # Test loop detection from automata.state import State from automata.fsm.fsm import NeFSM s = State() k = NeFSM(states={s}, alphabet={'a'}, transitions={(s, ''): {s}}, initial=s, accepting={}) assert not k.run('a'), k.dump() regex = '(a|b)*' #print_tree(parse_regex(regex)) k = compile_regex(regex) #k.render() k = compile_regex('a') l = k.to_dfsm() assert NeFSM.from_dfsm(l).to_regex() == 'a', NeFSM.from_dfsm(l).to_regex() k = compile_regex('abc')