From 19df3f93d216556d396872f3a616af3a5b542273 Mon Sep 17 00:00:00 2001 From: Nikolai Ponomarev Date: Fri, 9 Feb 2024 20:43:48 +0300 Subject: [PATCH 01/11] Fix trailing whitespaces --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b18fdf77f..ffc866079 100644 --- a/README.md +++ b/README.md @@ -168,28 +168,28 @@ - Синтаксический анализ языков программирования: в компиляторах, интерпертаторах, средах разработки, других инстументах. - Анализ естественных языков. Активность в этой области несколько спала, так как на передний план сейчас вышли различные методы машинного обучения. - Однако и в этой области ведуться работы.Например, [International Conference on Parsing Technologies](http://www.wikicfp.com/cfp/program?id=1853). + Однако и в этой области ведуться работы.Например, [International Conference on Parsing Technologies](http://www.wikicfp.com/cfp/program?id=1853). - Статический анализ кода. - Различные задачи межпроцедурного анализа. Основной подход --- language reachability. Основоположник --- Томас Репс. Примеры работ. - Thomas Reps. 1997. Program analysis via graph reachability. In Proceedings of the 1997 international symposium on Logic programming (ILPS ’97). MIT Press, Cambridge, MA, USA, 5–19. - Qirun Zhang and Zhendong Su. 2017. Context-sensitive data-dependence analysis via linear conjunctive language reachability. In Proceedings of the 44th ACM SIGPLAN Symposium on Principles of Programming Languages (POPL 2017). Association for Computing Machinery, New York, NY, USA, 344–358. DOI:https://doi.org/10.1145/3009837.3009848 - Kai Wang, Aftab Hussain, Zhiqiang Zuo, Guoqing Xu, and Ardalan Amiri Sani. 2017. Graspan: A Single-machine Disk-based Graph System for Interprocedural Static Analyses of Large-scale Systems Code. In Proceedings of the Twenty-Second International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS ’17). Association for Computing Machinery, New York, NY, USA, 389–404. DOI:https://doi.org/10.1145/3037697.3037744 - - Lu Y., Shang L., Xie X., Xue J. (2013) An Incremental Points-to Analysis with CFL-Reachability. In: Jhala R., De Bosschere K. (eds) Compiler Construction. CC 2013. Lecture Notes in Computer Science, vol 7791. Springer, Berlin, Heidelberg + - Lu Y., Shang L., Xie X., Xue J. (2013) An Incremental Points-to Analysis with CFL-Reachability. In: Jhala R., De Bosschere K. (eds) Compiler Construction. CC 2013. Lecture Notes in Computer Science, vol 7791. Springer, Berlin, Heidelberg - Интерливинг (или шафл) языков для верификаци многопоточных программ. - [Approximating the Shuffle of Context-free Languages to Find Bugs in Concurrent Recursive Programs](http://uu.diva-portal.org/smash/get/diva2:442518/FULLTEXT01.pdf) - Flick N.E. (2015) Quotients of Unbounded Parallelism. In: Leucker M., Rueda C., Valencia F. (eds) Theoretical Aspects of Computing - ICTAC 2015. ICTAC 2015. Lecture Notes in Computer Science, vol 9399. Springer, Cham - + - Система типов Java: [Radu Grigore, Java Generics are Turing Complete](https://arxiv.org/abs/1605.05274). - Графовые базы данных. Поиск путей с ограничениями. - Maurizio Nolé and Carlo Sartiani. 2016. Regular Path Queries on Massive Graphs. In Proceedings of the 28th International Conference on Scientific and Statistical Database Management (SSDBM ’16). Association for Computing Machinery, New York, NY, USA, Article 13, 1–12. DOI:https://doi.org/10.1145/2949689.2949711 - Jochem Kuijpers, George Fletcher, Nikolay Yakovets, and Tobias Lindaaker. 2019. An Experimental Study of Context-Free Path Query Evaluation Methods. In Proceedings of the 31st International Conference on Scientific and Statistical Database Management (SSDBM ’19). Association for Computing Machinery, New York, NY, USA, 121–132. DOI:https://doi.org/10.1145/3335783.3335791 - [Jelle Hellings. Querying for Paths in Graphs using Context-Free Path Queries.](https://arxiv.org/abs/1502.02242) - + - Биоинформатика. В основном это анализ геномных и белковых последовательностей. - [Witold Dyrka, Mateusz Pyzik, Francois Coste, and Hugo Talibart. Estimating probabilistic context-free grammars for proteins using contact map constraints.](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6428041/) - [James WJ Anderson, Paula Tataru, Joe Staines, Jotun Hein, and Rune Lyngso. Evolving stochastic context-free grammars for RNA secondary structure prediction.](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3464655/) - - [Ryan Zier-Vogel. Predicting RNA secondary structure using a stochastic conjunctive grammar.](https://www.semanticscholar.org/paper/Predicting-RNA-secondary-structure-using-a-grammar-Zier-Vogel/90bb312cb1a0f61eddb7a8b5b782bb40630894dd). + - [Ryan Zier-Vogel. Predicting RNA secondary structure using a stochastic conjunctive grammar.](https://www.semanticscholar.org/paper/Predicting-RNA-secondary-structure-using-a-grammar-Zier-Vogel/90bb312cb1a0f61eddb7a8b5b782bb40630894dd). - Машинное обучение. - [Matt J. Kusner, Brooks Paige, José Miguel Hernández-Lobato. Grammar Variational Autoencoder](https://arxiv.org/abs/1703.01925). Опубликована в 2017 году и уже [больше 950 цитирований.](https://scholar.google.com/scholar?cites=4080460899049502885&as_sdt=2005&sciodt=0,5&hl=ru) @@ -203,17 +203,17 @@ - [HYPEREDGE REPLACEMENT GRAPH GRAMMARS](https://people.cs.umu.se/drewes/biblio/ps-files/hrg.pdf) - [(Re)introducing Regular Graph Languages](https://www.aclweb.org/anthology/W17-3410.pdf) - [Hyperedge Replacement: Grammars and Languages](https://www.springer.com/gp/book/9783540560050) - - $\ldots$ + - $\ldots$ - Теория групп. Как правило, это проблема слов группы или дополнение к ней. - Anisimov, A.V. Group languages. Cybern Syst Anal (1971) 7: 594. - David E. Muller, Paul E. Schupp, Groups, the Theory of ends, and context-free languages, Journal of Computer and System Sciences, Volume 26, Issue 3, 1983, Pages 295-310, ISSN 0022-0000 - HOLT, D., REES, S., ROVER, C., \& THOMAS, R. (2005). GROUPS WITH CONTEXT-FREE CO-WORD PROBLEM. Journal of the London Mathematical Society, 71(3), 643-657. doi:10.1112/S002461070500654X - [Groups with Context-Free Co-Word Problem and Embeddings into Thompson's Group V](https://arxiv.org/abs/1407.7745) - [Kropholler, R. \& Spriano, D. (2019). Closure properties in the class of multiple context-free groups. Groups Complexity Cryptology, 11(1), pp. 1-15. Retrieved 13 Feb. 2020, from doi:10.1515/gcc-2019-2004](https://www.degruyter.com/view/j/gcc.2019.11.issue-1/gcc-2019-2004/gcc-2019-2004.xml) - - [Word problems of groups, formal languages and decidability](https://personalpages.manchester.ac.uk/staff/Mark.Kambites/events/nbsan/nbsan17_thomas.pdf) + - [Word problems of groups, formal languages and decidability](https://personalpages.manchester.ac.uk/staff/Mark.Kambites/events/nbsan/nbsan17_thomas.pdf) - Прочая интересная математика. - Немного топологии в теории формальных языков: [Salvati S. On is an n-MCFL. – 2018.](https://hal.archives-ouvertes.fr/hal-01771670/) - Salvati S. MIX is a 2-MCFL and the word problem in Z2 is captured by the IO and the OI hierarchies //Journal of Computer and System Sciences. -- 2015. -- Т. 81. -- \textnumero. 7. -- С. 1252-1277. - О том, как задачи из теории графов связаны с теорией формальных языков: Abboud, Amir \& Backurs, Arturs \& Williams, Virginia. (2015). If the Current Clique Algorithms are Optimal, So is Valiant's Parser. 98-117. 10.1109/FOCS.2015.16. - - [A context-free grammar for the Ramanujan-Shor polynomials](https://www.sciencedirect.com/science/article/abs/pii/S0196885819300739) + - [A context-free grammar for the Ramanujan-Shor polynomials](https://www.sciencedirect.com/science/article/abs/pii/S0196885819300739) From 7280de870bd19ec989d15ca894fd1186e4313c7d Mon Sep 17 00:00:00 2001 From: Nikolai Ponomarev Date: Fri, 9 Feb 2024 20:50:48 +0300 Subject: [PATCH 02/11] Bump pre-commit hooks Bumping black probably a must because of unpinned requirements.txt --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f2f1f4a31..95acb0a1a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,12 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.4.0 + rev: v4.5.0 hooks: - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - id: requirements-txt-fixer - repo: https://github.com/psf/black - rev: 22.3.0 + rev: 24.1.1 hooks: - id: black From 4f7c6b85139c890334d3bc8e21c21026380a2358 Mon Sep 17 00:00:00 2001 From: Nikolai Ponomarev Date: Fri, 9 Feb 2024 21:39:25 +0300 Subject: [PATCH 03/11] Make README more precise about tests --- README.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ffc866079..a6a885ef3 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,20 @@ - Сторонние пакеты из `requirements.txt` файла - Английский язык для документации или самодокументирующийся код +## Содержание + +* [Из чего складывается оценка за курс](#из-чего-складывается-оценка-за-курс) + * [Летучки](#летучки) + * [Домашние практические работы](#домашние-практические-работы) +* [Работа с проектом](#работа-с-проектом) +* [Домашние практические работы](#домашние-практические-работы-1) +* [Код](#код) +* [Тесты](#тесты) +* [Эксперименты](#эксперименты) +* [Структура репозитория](#структура-репозитория) +* [Контакты](#контакты) +* [Вместо введения](#вместо-введения) + ## Из чего складывается оценка за курс Оценка за курс складывается из баллов, полученных за работу в семестре. Баллы начисляются за следующее. @@ -66,7 +80,7 @@ ### Домашние практические работы Работы бывают двух типов: -- С полностью автоматической проверкой. Подразумевается, что к этим задачам известен набор тестов и если он проходит, то задача засчитывается. Количество баллов за такие задачи не менее 60. То есть написав все летучки и сдав все такие задачи можно гарантированно получить 3 (E-D) за курс. +- С полностью автоматической проверкой. Подразумевается, что к этим задачам известны название и сигнатуры функций, а также набор тестов; если тесты проходят, то задача засчитывается. Количество баллов за такие задачи не менее 60. То есть написав все летучки и сдав все такие задачи можно гарантированно получить 3 (E-D) за курс. - Требующие проверки преподавателем или ассистентом. Как правило, это задачи на постановку экспериментов или разработку относительно нетривиальных решений. Они основаны на задачах предыдущего типа, потому решать их в изоляции затруднительно. У всех задач есть дедлайн (как правило --- неделя с момента, когда она была задана) после которого максимальный балл за задачу падает в два раза. @@ -123,6 +137,22 @@ ## Тесты +Тесты бывают двух видов: заготовленные преподавателем и ваши собственные. + +Заготовленные тесты существуют в папке `tests/autotests` и используются для проверки задач с полностью автоматической проверкой. +При работе с ними следует соблюдать следующие правила: +- В данных тестах обычно можно изменять только одно --- блок + ```python + try: + from project.task2 import regex_to_dfa, graph_to_nfa + except ImportError: + pytestmark = pytest.mark.skip("Task 2 is not ready to test!") + ``` + В нём необходимо указать из какого(их) модуля(ей) импортировать требуемые функции, в ином случае тесты пропускаются. +- В случае, если вы нашли ошибку **И** готовы её исправить, файл можно изменять, а затем отправлять изменение с помощью Pull Request в основной репозиторий. +- Если же вы нашли ошибку и не готовы заниматься её исправлением, то об этом нужно срочно сообщить преподавателю и не предпринимать других действий! + +К вашим собственным тестам применяются следующие правила: - Тесты для домашних заданий размещайте в папке `tests`. - Формат именования файлов с тестами `test_[какой модуль\класс\функцию тестирует].py`. - Для работы с тестами рекомендуется использовать [`pytest`](https://docs.pytest.org/en/6.2.x/). @@ -149,6 +179,7 @@ ├── scripts - вспомогательные скрипты для автоматизации разработки ├── tasks - файлы с описанием домашних заданий ├── tests - директория для unit-тестов домашних работ +│ └── autotests - директория с автотестами для домашних работ ├── README.md - основная информация о проекте └── requirements.txt - зависимости для настройки репозитория ``` From 3a60b5dcb299b1acb6a41be84b12be36d8285af7 Mon Sep 17 00:00:00 2001 From: Nikolai Ponomarev Date: Sat, 10 Feb 2024 12:03:35 +0300 Subject: [PATCH 04/11] Update task2.md --- tasks/task2.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tasks/task2.md b/tasks/task2.md index a2da608c0..99d2c6fd6 100644 --- a/tasks/task2.md +++ b/tasks/task2.md @@ -1,11 +1,23 @@ # Задача 2. Построение детерминированного конечного автомата по регулярному выражению и недетерминированного конечного автомата по графу -* **Мягкий дедлайн**: 18.09.2023, 23:59 -* **Жёсткий дедлайн**: 21.09.2023, 23:59 +* **Мягкий дедлайн**: 21.02.2024, 23:59 +* **Жёсткий дедлайн**: 28.02.2024, 23:59 * Полный балл: 5 ## Задача -- [ ] Используя возможности [pyformlang](https://pyformlang.readthedocs.io/en/latest/) реализовать **функцию** построения минимального ДКА по заданному регулярному выражению. [Формат регулярного выражения.](https://pyformlang.readthedocs.io/en/latest/usage.html#regular-expression). +- [ ] Используя возможности [pyformlang](https://pyformlang.readthedocs.io/en/latest/) реализовать **функцию** построения минимального ДКА по заданному регулярному выражению. [Формат регулярного выражения](https://pyformlang.readthedocs.io/en/latest/usage.html#regular-expression). + - Требуемая функция: + ```python + def regex_to_dfa(regex: str) -> DeterministicFiniteAutomaton: + pass + ``` - [ ] Используя возможности [pyformlang](https://pyformlang.readthedocs.io/en/latest/) реализовать **функцию** построения недетерминированного конечного автомата по [графу](https://networkx.org/documentation/stable/reference/classes/multidigraph.html), в том числе по любому из графов, которые можно получить, пользуясь функциональностью, реализованной в [Задаче 1](https://github.com/FormalLanguageConstrainedPathQuerying/formal-lang-course/blob/main/tasks/task1.md) (загруженный из набора данных по имени граф, сгенерированный синтетический граф). Предусмотреть возможность указывать стартовые и финальные вершины. Если они не указаны, то считать все вершины стартовыми и финальными. -- [ ] Добавить необходимые тесты. + - Требуемая функция: + ```python + def graph_to_nfa( + graph: MultiDiGraph, start_states: Set[int], final_states: Set[int] + ) -> NondeterministicFiniteAutomaton: + pass + ``` +- [ ] Добавить собственные тесты при необходимости. From bda65edad728c1be5986033059031b3a89cbc07b Mon Sep 17 00:00:00 2001 From: Nikolai Ponomarev Date: Mon, 12 Feb 2024 13:43:26 +0300 Subject: [PATCH 05/11] Add first part of tests for task 2 --- tests/autotests/test_task2.py | 95 +++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 tests/autotests/test_task2.py diff --git a/tests/autotests/test_task2.py b/tests/autotests/test_task2.py new file mode 100644 index 000000000..d68cf3a7f --- /dev/null +++ b/tests/autotests/test_task2.py @@ -0,0 +1,95 @@ +# This file contains test cases that you need to pass to get a grade +# You MUST NOT touch anything here except ONE block below +# You CAN modify this file IF AND ONLY IF you have found a bug and are willing to fix it +# Otherwise, please report it +from networkx import MultiDiGraph +from pyformlang.regular_expression import Regex +import pytest +import random +import itertools +import networkx as nx + +# Fix import statements in try block to run tests +try: + from project.task2 import regex_to_dfa, graph_to_nfa +except ImportError: + pytestmark = pytest.mark.skip("Task 2 is not ready to test!") + +REGEX_TO_TEST = [ + "(aa)*", + "a | a", + "a* | a", + "(ab) | (ac)", + "(ab) | (abc)", + "(abd) | (abc)", + "(abd*) | (abc*)", + "(abd)* | (abc)*", + "((abd) | (abc))*", + "a*a*", + "a*a*b", + "a* | (a | b)*", + "a*(a | b)*", + "(a | c)*(a | b)*", +] + + +@pytest.mark.skip("") +class TestRegexToDfa: + @pytest.mark.parametrize("regex_str", REGEX_TO_TEST, ids=lambda regex: regex) + def test(self, regex_str: str) -> None: + regex = Regex(regex_str) + regex_cfg = regex.to_cfg() + regex_words = regex_cfg.get_words() + + if regex_cfg.is_finite(): + all_word_parts = list(regex_words) + word_parts = random.choice(all_word_parts) + else: + index = random.randint(0, 2**9) + word_parts = next(itertools.islice(regex_words, index, None)) + + word = map(lambda x: x.value, word_parts) + + dfa = regex_to_dfa(regex_str) + + minimized_dfa = dfa.minimize() + assert dfa.is_deterministic() + assert dfa.is_equivalent_to(minimized_dfa) + assert dfa.accepts(word) + + +LABELS = ["a", "b", "c", "x", "y", "z", "alpha", "beta", "gamma", "ɛ"] + + +@pytest.fixture(scope="class", params=range(2)) +def graph(request) -> MultiDiGraph: + n_of_nodes = random.randint(5, 20) + graph = nx.scale_free_graph(n_of_nodes) + + for _, _, data in graph.edges(data=True): + data["label"] = LABELS[random.randint(0, len(LABELS) - 1)] + + return graph + + +class TestGraphToNfa: + def test_random( + self, + graph: MultiDiGraph, + ) -> None: + # print(graph.edges(data=True)) + assert True + + def test_all(self, graph: MultiDiGraph) -> None: + for _, data in graph.nodes(data=True): + data["is_start"] = True + data["is_final"] = True + # print(graph.nodes(data=True)) + + starting_node = random.choice(list(graph.nodes)) + # print(starting_node) + p = nx.dfs_edges(graph, starting_node) + path = itertools.takewhile(lambda node: not node[1]["is_final"], p) + print(list(p)) + + assert True From c401a4746856951526ca3c030d8ab74832df1045 Mon Sep 17 00:00:00 2001 From: Efim Kubishkin Date: Tue, 13 Feb 2024 22:22:41 +0300 Subject: [PATCH 06/11] Add tests for second part of task2 Function get_all_words_by_n_steps generates all reachable words in graph by n steps. Among them randomly choose some word and check that nfa from graph accept it --- tests/autotests/test_task2.py | 73 ++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/tests/autotests/test_task2.py b/tests/autotests/test_task2.py index d68cf3a7f..e89f95015 100644 --- a/tests/autotests/test_task2.py +++ b/tests/autotests/test_task2.py @@ -2,6 +2,7 @@ # You MUST NOT touch anything here except ONE block below # You CAN modify this file IF AND ONLY IF you have found a bug and are willing to fix it # Otherwise, please report it +import pyformlang.finite_automaton from networkx import MultiDiGraph from pyformlang.regular_expression import Regex import pytest @@ -58,38 +59,72 @@ def test(self, regex_str: str) -> None: assert dfa.accepts(word) -LABELS = ["a", "b", "c", "x", "y", "z", "alpha", "beta", "gamma", "ɛ"] +LABELS = ["a", "b", "c", "x", "y", "z", "alpha", "beta", "gamma"] -@pytest.fixture(scope="class", params=range(2)) +@pytest.fixture(scope="class", params=range(5)) def graph(request) -> MultiDiGraph: n_of_nodes = random.randint(5, 20) graph = nx.scale_free_graph(n_of_nodes) for _, _, data in graph.edges(data=True): - data["label"] = LABELS[random.randint(0, len(LABELS) - 1)] + data["label"] = random.choice(LABELS) return graph +def take_a_step(graph: MultiDiGraph, node): + for node_to, edge_dict in dict(graph[node]).items(): + for edge_data in edge_dict.values(): + yield {"node_to": node_to, "label": edge_data["label"]} + + +def get_all_words_by_n_steps(graph: MultiDiGraph, n: int) -> list[str]: + start_nodes = list(map(lambda x: x[0], graph.nodes(data="is_start"))) + + def is_final_node(node): + return graph.nodes(data=True)[node]["is_final"] + + def get_all_words_by_node(node, word): + for trans in take_a_step(graph, node): + tmp = word.copy() + tmp.append(trans["label"]) + if is_final_node(trans["node_to"]): + yield tmp.copy() + yield from get_all_words_by_node(trans["node_to"], tmp.copy()) + + result = list() + for start in start_nodes: + result.extend(itertools.islice(get_all_words_by_node(start, []), 0, n)) + return result + + class TestGraphToNfa: + def test_not_specified(self, graph: MultiDiGraph) -> None: + nfa: pyformlang.finite_automaton.NondeterministicFiniteAutomaton = graph_to_nfa( + graph, set(), set() + ) + words = get_all_words_by_n_steps(graph, random.randint(10, 100)) + word = random.choice(words) + assert nfa.accepts(word) + def test_random( self, graph: MultiDiGraph, ) -> None: - # print(graph.edges(data=True)) - assert True - - def test_all(self, graph: MultiDiGraph) -> None: - for _, data in graph.nodes(data=True): - data["is_start"] = True - data["is_final"] = True - # print(graph.nodes(data=True)) - - starting_node = random.choice(list(graph.nodes)) - # print(starting_node) - p = nx.dfs_edges(graph, starting_node) - path = itertools.takewhile(lambda node: not node[1]["is_final"], p) - print(list(p)) - - assert True + start_nodes = set( + random.choices( + list(graph.nodes().keys()), k=random.randint(1, len(graph.nodes)) + ) + ) + final_nodes = set( + random.choices( + list(graph.nodes().keys()), k=random.randint(1, len(graph.nodes)) + ) + ) + nfa: pyformlang.finite_automaton.NondeterministicFiniteAutomaton = graph_to_nfa( + graph, start_nodes, final_nodes + ) + words = get_all_words_by_n_steps(graph, random.randint(10, 100)) + word = random.choice(words) + assert nfa.accepts(word) From 983c7c557fe167a848c9fd2b70b8a58e0194b3c5 Mon Sep 17 00:00:00 2001 From: Nikolai Ponomarev Date: Tue, 13 Feb 2024 22:42:56 +0300 Subject: [PATCH 07/11] Add epsilon-transition generation --- tests/autotests/test_task2.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/autotests/test_task2.py b/tests/autotests/test_task2.py index e89f95015..1e7ae05db 100644 --- a/tests/autotests/test_task2.py +++ b/tests/autotests/test_task2.py @@ -59,7 +59,7 @@ def test(self, regex_str: str) -> None: assert dfa.accepts(word) -LABELS = ["a", "b", "c", "x", "y", "z", "alpha", "beta", "gamma"] +LABELS = ["a", "b", "c", "x", "y", "z", "alpha", "beta", "gamma", "ɛ"] @pytest.fixture(scope="class", params=range(5)) @@ -88,7 +88,9 @@ def is_final_node(node): def get_all_words_by_node(node, word): for trans in take_a_step(graph, node): tmp = word.copy() - tmp.append(trans["label"]) + label = trans["label"] + if label != "ɛ": + tmp.append(label) if is_final_node(trans["node_to"]): yield tmp.copy() yield from get_all_words_by_node(trans["node_to"], tmp.copy()) From 23b9ad9c30115c72be6e981589ebe6ee49c71cfc Mon Sep 17 00:00:00 2001 From: Efim Kubishkin Date: Thu, 15 Feb 2024 17:08:05 +0300 Subject: [PATCH 08/11] Fix second part of task2 Delete skipping of first part. Move some helpers functions into GraphWordsHelper class --- tests/autotests/test_task2.py | 94 +++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 33 deletions(-) diff --git a/tests/autotests/test_task2.py b/tests/autotests/test_task2.py index 1e7ae05db..285a01950 100644 --- a/tests/autotests/test_task2.py +++ b/tests/autotests/test_task2.py @@ -34,7 +34,6 @@ ] -@pytest.mark.skip("") class TestRegexToDfa: @pytest.mark.parametrize("regex_str", REGEX_TO_TEST, ids=lambda regex: regex) def test(self, regex_str: str) -> None: @@ -62,43 +61,64 @@ def test(self, regex_str: str) -> None: LABELS = ["a", "b", "c", "x", "y", "z", "alpha", "beta", "gamma", "ɛ"] -@pytest.fixture(scope="class", params=range(5)) -def graph(request) -> MultiDiGraph: - n_of_nodes = random.randint(5, 20) - graph = nx.scale_free_graph(n_of_nodes) +class GraphWordsHelper: + graph = None + all_paths = None - for _, _, data in graph.edges(data=True): - data["label"] = random.choice(LABELS) + def __init__(self, graph: MultiDiGraph): + self.graph = graph + self.all_paths = nx.shortest_path(graph) - return graph + def is_reachable(self, source, target): + if source not in self.all_paths.keys(): + return False + return target in self.all_paths[source].keys() + def _take_a_step(self, node): + for node_to, edge_dict in dict(self.graph[node]).items(): + for edge_data in edge_dict.values(): + yield {"node_to": node_to, "label": edge_data["label"]} -def take_a_step(graph: MultiDiGraph, node): - for node_to, edge_dict in dict(graph[node]).items(): - for edge_data in edge_dict.values(): - yield {"node_to": node_to, "label": edge_data["label"]} + def _is_final_node(self, node): + return self.graph.nodes(data=True)[node]["is_final"] - -def get_all_words_by_n_steps(graph: MultiDiGraph, n: int) -> list[str]: - start_nodes = list(map(lambda x: x[0], graph.nodes(data="is_start"))) - - def is_final_node(node): - return graph.nodes(data=True)[node]["is_final"] - - def get_all_words_by_node(node, word): - for trans in take_a_step(graph, node): + def generate_words_by_node(self, node, word=None): + if word is None: + word = list() + for trans in self._take_a_step(node): tmp = word.copy() label = trans["label"] if label != "ɛ": tmp.append(label) - if is_final_node(trans["node_to"]): + if self._is_final_node(trans["node_to"]): yield tmp.copy() - yield from get_all_words_by_node(trans["node_to"], tmp.copy()) + yield from self.generate_words_by_node(trans["node_to"], tmp.copy()) + + def take_words_by_node(self, node, n): + final_nodes = list(map(lambda x: x[0], self.graph.nodes(data="is_final"))) + if any( + map(lambda final_node: self.is_reachable(node, final_node), final_nodes) + ): + return itertools.islice(self.generate_words_by_node(node), 0, n) + return [] + + def get_all_words_less_then_n(self, n: int) -> list[str]: + start_nodes = list(map(lambda x: x[0], self.graph.nodes(data="is_start"))) + result = list() + for start in start_nodes: + result.extend(self.take_words_by_node(start, n)) + return result - result = list() - for start in start_nodes: - result.extend(itertools.islice(get_all_words_by_node(start, []), 0, n)) - return result + +@pytest.fixture(scope="class", params=range(5)) +def graph(request) -> MultiDiGraph: + n_of_nodes = random.randint(1, 20) + graph = nx.scale_free_graph(n_of_nodes) + + for _, _, data in graph.edges(data=True): + data["label"] = random.choice(LABELS) + + return graph class TestGraphToNfa: @@ -106,9 +126,13 @@ def test_not_specified(self, graph: MultiDiGraph) -> None: nfa: pyformlang.finite_automaton.NondeterministicFiniteAutomaton = graph_to_nfa( graph, set(), set() ) - words = get_all_words_by_n_steps(graph, random.randint(10, 100)) - word = random.choice(words) - assert nfa.accepts(word) + words_helper = GraphWordsHelper(graph) + words = words_helper.get_all_words_less_then_n(random.randint(10, 100)) + if len(words) == 0: + assert nfa.is_empty() + else: + word = random.choice(words) + assert nfa.accepts(word) def test_random( self, @@ -127,6 +151,10 @@ def test_random( nfa: pyformlang.finite_automaton.NondeterministicFiniteAutomaton = graph_to_nfa( graph, start_nodes, final_nodes ) - words = get_all_words_by_n_steps(graph, random.randint(10, 100)) - word = random.choice(words) - assert nfa.accepts(word) + words_helper = GraphWordsHelper(graph) + words = words_helper.get_all_words_less_then_n(random.randint(10, 100)) + if len(words) == 0: + assert nfa.is_empty() + else: + word = random.choice(words) + assert nfa.accepts(word) From 1a41a23e07d46ee74d5ef3ba49d27daae5f621cf Mon Sep 17 00:00:00 2001 From: Semyon Date: Mon, 19 Feb 2024 10:38:54 +0300 Subject: [PATCH 09/11] =?UTF-8?q?=D0=90=D0=BA=D1=82=D1=83=D0=B0=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D1=8B=D0=B5=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=B2=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87=D0=B5=205.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tasks/task5.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/task5.md b/tasks/task5.md index 6319c6a43..bc128cb72 100644 --- a/tasks/task5.md +++ b/tasks/task5.md @@ -37,7 +37,7 @@ - [ ] Создать Python notebook, подключить необходимые зависимости. - [ ] Подключить решения из предыдущих работ. - [ ] Сформировать набор данных. - - [ ] Выбрать некоторые графы из [набора](https://jetbrains-research.github.io/CFPQ_Data/dataset/index.html). Не забудьте обосновать, почему выбрали именно эти графы. + - [ ] Выбрать некоторые графы из [набора](https://formallanguageconstrainedpathquerying.github.io/CFPQ_Data/graphs/index.html). Не забудьте обосновать, почему выбрали именно эти графы. - [ ] Используя функцию из первой домашней работы узнать метки рёбер графов и на основе этой информации сформулировать не менее четырёх различных запросов к каждому графу. Лучше использовать наиболее часто встречающиеся метки. Требования к запросам: - Запросы ко всем графам должны следовать некоторому общему шаблону. Например, если есть графы ```g1``` и ```g2``` с различными наборами меток, то ожидается, что запросы к ним будут выглядеть, например, так: - ```g1```: @@ -49,7 +49,7 @@ - ```(m1 | m3)+ m2*``` - ```m1 m2 m3 (m3|m1)*``` - В запросах должны использоваться все общепринятые конструкции регулярных выражений (замыкание, конкатенация, альтернатива). То есть хотя бы в одном запросе к каждому графу должна быть каждая из этих конструкций. - - [ ] Для генерации множеств стартовых вершин воспользоваться [этой функцией](https://jetbrains-research.github.io/CFPQ_Data/reference/graphs/generated/cfpq_data.graphs.utils.multiple_source_utils.html#cfpq_data.graphs.utils.multiple_source_utils.generate_multiple_source). Не забывайте, что от того, как именно устроено стартовое множество, сильно зависит время вычисления запроса. + - [ ] Для генерации множеств стартовых вершин воспользоваться [этой функцией](https://formallanguageconstrainedpathquerying.github.io/CFPQ_Data/reference/graphs/generated/cfpq_data.graphs.utils.multiple_source_utils.html#cfpq_data.graphs.utils.multiple_source_utils.generate_multiple_source). Не забывайте, что от того, как именно устроено стартовое множество, сильно зависит время вычисления запроса. - [ ] Сформулировать этапы эксперимента. Что нужно сделать, чтобы ответить на поставленные вопросы? Почему? - [ ] Провести необходимые эксперименты, замеры - [ ] Оформить результаты экспериментов From e745620482f0ecb81fc22ec1bae7abbc9c28be2a Mon Sep 17 00:00:00 2001 From: Semyon Date: Mon, 19 Feb 2024 19:02:26 +0300 Subject: [PATCH 10/11] Update task2.md --- tasks/task2.md | 1 - 1 file changed, 1 deletion(-) diff --git a/tasks/task2.md b/tasks/task2.md index 99d2c6fd6..67afbccc1 100644 --- a/tasks/task2.md +++ b/tasks/task2.md @@ -1,6 +1,5 @@ # Задача 2. Построение детерминированного конечного автомата по регулярному выражению и недетерминированного конечного автомата по графу -* **Мягкий дедлайн**: 21.02.2024, 23:59 * **Жёсткий дедлайн**: 28.02.2024, 23:59 * Полный балл: 5 From 7c7f67ac1ef4a087ca335d17b0611c17554dd4f3 Mon Sep 17 00:00:00 2001 From: Semyon Date: Mon, 19 Feb 2024 19:51:25 +0300 Subject: [PATCH 11/11] Update task2.md --- tasks/task2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/task2.md b/tasks/task2.md index 67afbccc1..d55f6b0bb 100644 --- a/tasks/task2.md +++ b/tasks/task2.md @@ -1,6 +1,6 @@ # Задача 2. Построение детерминированного конечного автомата по регулярному выражению и недетерминированного конечного автомата по графу -* **Жёсткий дедлайн**: 28.02.2024, 23:59 +* **Жёсткий дедлайн**: 21.02.2024, 23:59 * Полный балл: 5 ## Задача