diff --git a/tasks/task3.md b/tasks/task3.md index 58b7dd44f..f39fd69ec 100644 --- a/tasks/task3.md +++ b/tasks/task3.md @@ -6,10 +6,12 @@ ## Задача - [ ] Реализовать тип (FiniteAutomaton), представляющий конечный автомат в виде разреженной матрицы смежности из [sciPy](https://docs.scipy.org/doc/scipy/reference/sparse.html) и информации о стартовых и финальных вершинах. У типа должны быть конструкторы от DeterministicFiniteAutomaton и NondeterministicFiniteAutomaton из [Задачи 2](https://github.com/FormalLanguageConstrainedPathQuerying/formal-lang-course/blob/main/tasks/task2.md). -- [ ] Реализовать функцию-интерпретатор для типа FiniteAutomaton, выясняющую, принимает ли автомат заданную строку. - - Требуемая функция: +- [ ] Реализовать функцию-интерпретатор для типа FiniteAutomaton, выясняющую, принимает ли автомат заданную строку и является ли язык, задающийся автоматом, пустым. Для реализации последней функции рекомендуется использовать транзитивное замыкание матрицы смежности. + - Требуемые функции: ```python - def accept(self, word: Iterable[Symbol]) -> bool: + def accepts(self, word: Iterable[Symbol]) -> bool: + pass + def is_empty(self) -> bool: pass ``` - [ ] Используя [разреженные матрицы из sciPy](https://docs.scipy.org/doc/scipy/reference/sparse.html) реализовать **функцию** пересечения двух конечных автоматов через тензорное произведение. @@ -22,8 +24,8 @@ - [ ] На основе предыдущей функции реализовать **функцию** выполнения регулярных запросов к графам: по графу с заданными стартовыми и финальными вершинами и регулярному выражению вернуть те пары вершин из заданных стартовых и финальных, которые связанны путём, формирующем слово из языка, задаваемого регулярным выражением. - Требуемая функция: ```python - def paths_ends(graph: MultiDiGraph, - regex:str) -> list[tuple[NodeView, NodeView]]: + def paths_ends(graph: MultiDiGraph, start_nodes: set[int], + final_nodes: set[int], regex:str) -> list[tuple[NodeView, NodeView]]: pass ``` diff --git a/tests/autotests/test_task3.py b/tests/autotests/test_task3.py index bfb9a1b6f..5a04f6b28 100644 --- a/tests/autotests/test_task3.py +++ b/tests/autotests/test_task3.py @@ -12,7 +12,7 @@ # Fix import statements in try block to run tests try: - from project.task3 import intersect_automata, paths_ends, FiniteAutomaton + from project.task3 import intersect_automata, FiniteAutomaton from project.task2 import regex_to_dfa except ImportError: pytestmark = pytest.mark.skip("Task 3 is not ready to test!") @@ -40,19 +40,28 @@ class TestIntersect: @pytest.mark.parametrize( "regex_str1, regex_str2", REGEX_TO_TEST, - ids=lambda regex_tuple: (regex_tuple[0], regex_tuple[1]), + ids=lambda regex_tuple: regex_tuple, ) def test(self, regex_str1: str, regex_str2: str) -> None: + dfa1 = FiniteAutomaton(regex_to_dfa(regex_str1)) + dfa2 = FiniteAutomaton(regex_to_dfa(regex_str2)) + intersect_fa = intersect_automata(dfa1, dfa2) + regex1: Regex = Regex(regex_str1) regex2: Regex = Regex(regex_str2) cfg_of_regex1: pyformlang.cfg.CFG = regex1.to_cfg() - # I don`t know why, but intersection works only with regex or FA. Not with CFG intersect_cfg: pyformlang.cfg.CFG = cfg_of_regex1.intersection(regex2) - words = intersect_cfg.get_words(max_length=10**2) - word = map(lambda x: x.value, random.choice(words)) + words = intersect_cfg.get_words() + if intersect_cfg.is_finite(): + all_word_parts = list(words) + if len(all_word_parts) == 0: + assert intersect_fa.is_empty() + return + word_parts = random.choice(all_word_parts) + else: + index = random.randint(0, 2**9) + word_parts = next(itertools.islice(words, index, None)) - dfa1 = FiniteAutomaton(regex_to_dfa(regex_str1)) - dfa2 = FiniteAutomaton(regex_to_dfa(regex_str2)) - intersect_fa = intersect_automata(dfa1, dfa2) + word = map(lambda x: x.value, word_parts) assert intersect_fa.accepts(word)