def test_intersection_regex(self): """ Tests the intersection with a regex """ # pylint: disable=too-many-locals state_p = State("p") state_q = State("q") state_r = State("r") state_i = Symbol("i") state_e = Symbol("e") state_z = StackSymbol("Z") state_x0 = StackSymbol("X0") pda = PDA(states={state_p, state_q, state_r}, input_symbols={state_i, state_e}, stack_alphabet={state_z, state_x0}, start_state=state_p, start_stack_symbol=state_x0, final_states={state_r}) pda.add_transition(state_p, Epsilon(), state_x0, state_q, [state_z, state_x0]) pda.add_transition(state_q, state_i, state_z, state_q, [state_z, state_z]) pda.add_transition(state_q, state_e, state_z, state_q, []) pda.add_transition(state_q, Epsilon(), state_x0, state_r, []) state_s = finite_automaton.State("s") state_t = finite_automaton.State("t") i_dfa = finite_automaton.Symbol("i") e_dfa = finite_automaton.Symbol("e") dfa = finite_automaton.DeterministicFiniteAutomaton( states={state_s, state_t}, input_symbols={i_dfa, e_dfa}, start_state=state_s, final_states={state_s, state_t}) dfa.add_transition(state_s, i_dfa, state_s) dfa.add_transition(state_s, e_dfa, state_t) dfa.add_transition(state_t, e_dfa, state_t) new_pda = pda.intersection(dfa) pda_es = new_pda.to_empty_stack() cfg = pda_es.to_cfg() self.assertEqual(new_pda.get_number_transitions(), 6) self.assertEqual(len(new_pda.states), 5) self.assertEqual(len(new_pda.final_states), 2) self.assertEqual(len(new_pda.input_symbols), 2) self.assertEqual(len(new_pda.stack_symbols), 2) i_cfg = Terminal("i") e_cfg = Terminal("e") self.assertTrue(cfg.contains([i_cfg, i_cfg, e_cfg, e_cfg, e_cfg])) new_pda = pda.intersection( finite_automaton.DeterministicFiniteAutomaton()) self.assertEqual(new_pda.get_number_transitions(), 0)
def _process_to_enfa_when_no_son(self, s_from, s_to): if isinstance(self.head, pyformlang.regular_expression.regex_objects.Epsilon): self._add_epsilon_transition_in_enfa_between(s_from, s_to) elif not isinstance(self.head, pyformlang.regular_expression.regex_objects.Empty): symbol = finite_automaton.Symbol(self.head.value) self._enfa.add_transition(s_from, symbol, s_to)
def test_to_enfa0(self): """ Tests the transformation to a regex """ symb_a = finite_automaton.Symbol("a") symb_b = finite_automaton.Symbol("b") symb_c = finite_automaton.Symbol("c") epsilon = finite_automaton.Epsilon() regex = Regex("a|b") enfa = regex.to_epsilon_nfa() self.assertTrue(enfa.accepts([symb_a])) self.assertTrue(enfa.accepts([symb_b])) self.assertFalse(enfa.accepts([symb_c])) self.assertFalse(enfa.accepts([epsilon])) self.assertFalse(enfa.accepts([symb_a, symb_b])) regex = Regex("a b") enfa = regex.to_epsilon_nfa() self.assertFalse(enfa.accepts([symb_a])) self.assertFalse(enfa.accepts([symb_b])) self.assertTrue(enfa.accepts([symb_a, symb_b])) regex = Regex("a b c") enfa = regex.to_epsilon_nfa() self.assertFalse(enfa.accepts([symb_a, symb_b])) self.assertTrue(enfa.accepts([symb_a, symb_b, symb_c])) self.assertFalse(enfa.accepts([symb_a, symb_b, symb_a])) regex = Regex("(a b)|c") enfa = regex.to_epsilon_nfa() self.assertTrue(enfa.accepts([symb_a, symb_b])) self.assertFalse(enfa.accepts([symb_a, symb_c])) self.assertFalse(enfa.accepts([symb_b, symb_c])) self.assertTrue(enfa.accepts([symb_c])) regex = Regex("") enfa = regex.to_epsilon_nfa() self.assertFalse(enfa.accepts([symb_a])) self.assertFalse(enfa.accepts([symb_b])) self.assertFalse(enfa.accepts([symb_c])) self.assertFalse(enfa.accepts([])) regex = Regex("a*") enfa = regex.to_epsilon_nfa() self.assertTrue(enfa.accepts([symb_a])) self.assertTrue(enfa.accepts([])) self.assertTrue(enfa.accepts([symb_a, symb_a])) self.assertTrue(enfa.accepts([symb_a, symb_a, symb_a]))
def test_to_enfa1(self): """ Tests the transformation to a regex """ symb_a = finite_automaton.Symbol("a") symb_b = finite_automaton.Symbol("b") symb_c = finite_automaton.Symbol("c") regex = Regex("a**") enfa = regex.to_epsilon_nfa() self.assertTrue(enfa.accepts([symb_a])) self.assertTrue(enfa.accepts([])) self.assertTrue(enfa.accepts([symb_a, symb_a])) self.assertTrue(enfa.accepts([symb_a, symb_a, symb_a])) regex = Regex("a*b|c") enfa = regex.to_epsilon_nfa() self.assertTrue(enfa.accepts([symb_a, symb_a, symb_b])) self.assertTrue(enfa.accepts([symb_b])) self.assertTrue(enfa.accepts([symb_c])) self.assertFalse(enfa.accepts([symb_a, symb_a, symb_c])) regex = Regex("a*(b|c)") enfa = regex.to_epsilon_nfa() self.assertTrue(enfa.accepts([symb_a, symb_a, symb_b])) self.assertTrue(enfa.accepts([symb_b])) self.assertTrue(enfa.accepts([symb_c])) self.assertTrue(enfa.accepts([symb_a, symb_a, symb_c])) regex = Regex("a*.(b|c)") enfa = regex.to_epsilon_nfa() self.assertTrue(enfa.accepts([symb_a, symb_a, symb_b])) self.assertTrue(enfa.accepts([symb_b])) self.assertTrue(enfa.accepts([symb_c])) self.assertTrue(enfa.accepts([symb_a, symb_a, symb_c])) regex = Regex("a*.(b|c)epsilon") enfa = regex.to_epsilon_nfa() self.assertTrue(enfa.accepts([symb_a, symb_a, symb_b])) self.assertTrue(enfa.accepts([symb_b])) self.assertTrue(enfa.accepts([symb_c])) self.assertTrue(enfa.accepts([symb_a, symb_a, symb_c])) regex = Regex("$") enfa = regex.to_epsilon_nfa() self.assertFalse(enfa.accepts([symb_a])) self.assertFalse(enfa.accepts([symb_b])) self.assertFalse(enfa.accepts([symb_c])) self.assertTrue(enfa.accepts([]))
def intersection(self, other: Any) -> "PDA": """ Gets the intersection of the current PDA with something else Equivalent to: >> pda and regex Parameters ---------- other : any The other part of the intersection Returns ---------- new_pda : :class:`~pyformlang.pda.PDA` The pda resulting of the intersection Raises ---------- NotImplementedError When intersecting with something else than a regex or a finite automaton """ if isinstance(other, Regex): other = other.to_epsilon_nfa().to_deterministic() elif isinstance(other, FiniteAutomaton): if not other.is_deterministic(): other = other.to_deterministic() else: raise NotImplementedError start_state_other = other.start_states if len(start_state_other) == 0: return PDA() pda_state_converter = _PDAStateConverter(self._states, other.states) start_state_other = list(start_state_other)[0] final_state_other = other.final_states start = pda_state_converter.to_pda_combined_state( self._start_state, start_state_other) pda = PDA(start_state=start, start_stack_symbol=self._start_stack_symbol) symbols = self._input_symbols.copy() symbols.add(Epsilon()) to_process = [(self._start_state, start_state_other)] processed = {(self._start_state, start_state_other)} while to_process: state_in, state_dfa = to_process.pop() if (state_in in self._final_states and state_dfa in final_state_other): pda.add_final_state( pda_state_converter.to_pda_combined_state( state_in, state_dfa)) for symbol in symbols: if symbol == Epsilon(): symbol_dfa = finite_automaton.Epsilon() else: symbol_dfa = finite_automaton.Symbol(symbol.value) if symbol == Epsilon(): next_states_dfa = [state_dfa] else: next_states_dfa = other(state_dfa, symbol_dfa) if len(next_states_dfa) == 0: continue for stack_symbol in self._stack_alphabet: next_states_self = self._transition_function( state_in, symbol, stack_symbol) for next_state, next_stack in next_states_self: for next_state_dfa in next_states_dfa: pda.add_transition( pda_state_converter.to_pda_combined_state( state_in, state_dfa), symbol, stack_symbol, pda_state_converter.to_pda_combined_state( next_state, next_state_dfa), next_stack) if (next_state, next_state_dfa) not in processed: to_process.append((next_state, next_state_dfa)) processed.add((next_state, next_state_dfa)) return pda
def intersection(self, other: Any) -> "PDA": """ Gets the intersection of the language L generated by the \ current PDA when accepting by final state with something else Currently, it only works for regular languages (represented as \ regular expressions or finite automata) as the intersection \ between two PDAs is not context-free (it cannot be represented \ with a PDA). Equivalent to: >> pda and regex Parameters ---------- other : any The other part of the intersection Returns ---------- new_pda : :class:`~pyformlang.pda.PDA` The pda resulting of the intersection Raises ---------- NotImplementedError When intersecting with something else than a regex or a finite automaton """ if isinstance(other, regular_expression.Regex): enfa = other.to_epsilon_nfa() other = enfa.to_deterministic() elif isinstance(other, FiniteAutomaton): is_deterministic = other.is_deterministic() if not is_deterministic: other = other.to_deterministic() else: raise NotImplementedError start_state_other = other.start_states if len(start_state_other) == 0: return PDA() pda_state_converter = _PDAStateConverter(self._states, other.states) start_state_other = list(start_state_other)[0] final_state_other = other.final_states start = pda_state_converter.to_pda_combined_state(self._start_state, start_state_other) pda = PDA(start_state=start, start_stack_symbol=self._start_stack_symbol) symbols = self._input_symbols.copy() symbols.add(Epsilon()) to_process = [(self._start_state, start_state_other)] processed = {(self._start_state, start_state_other)} while to_process: state_in, state_dfa = to_process.pop() if (state_in in self._final_states and state_dfa in final_state_other): pda.add_final_state( pda_state_converter.to_pda_combined_state(state_in, state_dfa)) for symbol in symbols: if symbol == Epsilon(): symbol_dfa = finite_automaton.Epsilon() else: symbol_dfa = finite_automaton.Symbol(symbol.value) if symbol == Epsilon(): next_states_dfa = [state_dfa] else: next_states_dfa = other(state_dfa, symbol_dfa) if len(next_states_dfa) == 0: continue for stack_symbol in self._stack_alphabet: next_states_self = self._transition_function(state_in, symbol, stack_symbol) for next_state, next_stack in next_states_self: for next_state_dfa in next_states_dfa: pda.add_transition( pda_state_converter.to_pda_combined_state( state_in, state_dfa), symbol, stack_symbol, pda_state_converter.to_pda_combined_state( next_state, next_state_dfa), next_stack) if (next_state, next_state_dfa) not in processed: to_process.append((next_state, next_state_dfa)) processed.add((next_state, next_state_dfa)) return pda