From 34560d3628363f210fbf31d7c1b187d13c572b20 Mon Sep 17 00:00:00 2001 From: MaxanRus Date: Tue, 12 Oct 2021 17:54:14 +0300 Subject: [PATCH] fix some bugs and add big test --- CMakeLists.txt | 2 +- README.md | 4 +- src/DFA/DFAGraph.cpp | 7 ++- src/NFA/NFAGraph.cpp | 5 ++- src/converters/DFAToRegular.cpp | 71 ++++++++++++++++-------------- src/main.cpp | 70 +++++++---------------------- tests/GenericTest/GenericTest1.cpp | 69 +++++++++++++++++++++++++++++ 7 files changed, 133 insertions(+), 95 deletions(-) create mode 100644 tests/GenericTest/GenericTest1.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 703bedc..61f4f2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,6 @@ find_package(Threads REQUIRED) include_directories( "include" ${GTEST_INCLUDE_DIRS} - ${Boost_INCLUDE_DIR} ) set(CMAKE_CXX_STANDARD 17) @@ -39,6 +38,7 @@ set(TEST_FILES tests/invertFDFA/InvertFDFA.cpp tests/DFAToRegular/DFAToRegular2.cpp tests/DFAToMinDFA/CountSizesMinDFA.cpp + tests/GenericTest/GenericTest1.cpp ) add_executable(Formalang src/main.cpp ${SOURCE_FILES}) diff --git a/README.md b/README.md index c18d217..0d9dd89 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,9 @@ std::string reg = DFAGraphToRegular(std::move(DFA_graph)); // В регуляр RegularTree(reg).ToString() // Получится более красивая регулярка ``` Про сами регулярки + * - это плюс и звезда Клини. Их можно писать после слов, или после скобок. -abacaba* ~ (abacaba)\*. a(b)a\* ~ a(b)(a)\*. Для сложения языков используется |. Символом пустого слова является пробел. +abacaba\* ~ (abacaba)\*. a(b)a\* ~ a(b)(a)\*. Для сложения языков используется |. Символом пустого слова является пробел. + +Очень важное отличие, что у меня + \* привязываются не к букве, а к слову(например aba* это (aba)\*, а не ab(a)\* как вы ожидаете), это значительное отличие от существующих регулярок, но .ToString у RegularTree всегда + \* выдаст строку у которой перед + \* будет стоять скобочка Примеры регулярок diff --git a/src/DFA/DFAGraph.cpp b/src/DFA/DFAGraph.cpp index 011df6e..4b6c2fc 100644 --- a/src/DFA/DFAGraph.cpp +++ b/src/DFA/DFAGraph.cpp @@ -8,8 +8,7 @@ DFAGraph::DFAGraph(DFAGraph&& another) { std::swap(count_vertexes_, another.count_vertexes_); std::swap(vertexes_, another.vertexes_); std::swap(final_vertexes_, another.final_vertexes_); - // TODO - // std::swap(start_vertexes_, another.start_vertexes_); + std::swap(start_vertex_, another.start_vertex_); for (auto& i: vertexes_) i.second.owner_ = this; @@ -21,8 +20,7 @@ DFAGraph& DFAGraph::operator=(DFAGraph&& another) { std::swap(count_vertexes_, another.count_vertexes_); std::swap(vertexes_, another.vertexes_); std::swap(final_vertexes_, another.final_vertexes_); - // TODO - // std::swap(start_vertexes_, another.start_vertexes_); + std::swap(start_vertex_, another.start_vertex_); for (auto& i: vertexes_) i.second.owner_ = this; @@ -71,6 +69,7 @@ void DFAGraph::RemoveFinalVertex(size_t number) { void DFAGraph::RemoveStartVertex(size_t number) { if (start_vertex_ == number) { start_vertex_ = -1; + GetVertex(number).is_start_ = false; } } diff --git a/src/NFA/NFAGraph.cpp b/src/NFA/NFAGraph.cpp index 2d31831..874bcc4 100644 --- a/src/NFA/NFAGraph.cpp +++ b/src/NFA/NFAGraph.cpp @@ -185,7 +185,10 @@ void NFAGraph::CreateDotFile(const std::string& filename) const { for (auto& i: vertexes_) { for (auto& j: i.second.transitions_) { for (auto& k: j.second) { - out << i.first << "." << k << "[label=" << j.first << "]\n"; + if (j.first == ' ') + out << i.first << "->" << k << "[label=" << "EPS" << "]\n"; + else + out << i.first << "->" << k << "[label=" << j.first << "]\n"; } } if (i.second.IsStart() && i.second.IsFinal()) { diff --git a/src/converters/DFAToRegular.cpp b/src/converters/DFAToRegular.cpp index ffd6f0c..1f4d4be 100644 --- a/src/converters/DFAToRegular.cpp +++ b/src/converters/DFAToRegular.cpp @@ -1,19 +1,18 @@ #include "converters/DFAToRegular.hpp" +#include namespace converters { std::string DFAGraphToRegular(DFAGraph&& graph) { const size_t n = graph.GetCountVertexes() + 1; - std::string result = ""; - - std::vector>> transitions(n, - std::vector>(n)); std::map rename; size_t start = -1; for (int i = 0; i < n - 1; ++i) { if (graph.NotExistVertex(i)) continue; - if (graph.GetVertex(i).IsStart()) start = i; + if (graph.GetVertex(i).IsStart()) { + start = i; + } } rename[start] = 1; @@ -23,7 +22,8 @@ std::string DFAGraphToRegular(DFAGraph&& graph) { if (i == start) continue; rename[i] = cnt++; } - + std::vector>> transitions(cnt, + std::vector>(cnt)); for (int i = 0; i < n - 1; ++i) { if (graph.NotExistVertex(i)) continue; @@ -37,28 +37,28 @@ std::string DFAGraphToRegular(DFAGraph&& graph) { } } - for (int i = n - 1; i > 1; --i) { - std::vector>> new_transitions(n, - std::vector>(n)); - std::string loop = ""; + for (int i = cnt - 1; i > 1; --i) { + std::vector>> new_transitions(cnt, + std::vector>(cnt)); + std::string loop; if (transitions[i][i].size() != 0) { - for (const std::string s: transitions[i][i]) { + for (const std::string& s: transitions[i][i]) { loop += "("; loop += s; loop += ")"; loop += "|"; } - if (loop.size()) + if (loop.size()) { loop.pop_back(); - if (transitions[i][i].size() > 1) loop = "(" + loop + ")*"; - else - loop += "*"; + } else { + loop = ""; + } } for (int j = 0; j < i; ++j) { if (transitions[j][i].size() == 0) continue; - std::string j_to_i = ""; + std::string j_to_i; for (const std::string s: transitions[j][i]) { j_to_i += "("; j_to_i += s; @@ -67,13 +67,14 @@ std::string DFAGraphToRegular(DFAGraph&& graph) { } if (j_to_i.size()) j_to_i.pop_back(); - if (transitions[j][i].size() > 1) - j_to_i = "(" + j_to_i + ")"; + else + continue; + j_to_i = "(" + j_to_i + ")"; for (int k = 0; k < i; ++k) { - if (transitions[i][k].size() == 0) continue; + if (transitions[i][k].size() == 0) continue; std::string i_to_k = ""; - for (const std::string s: transitions[i][k]) { + for (const std::string& s: transitions[i][k]) { i_to_k += "("; i_to_k += s; i_to_k += ")"; @@ -81,8 +82,10 @@ std::string DFAGraphToRegular(DFAGraph&& graph) { } if (i_to_k.size()) i_to_k.pop_back(); - if (transitions[i][k].size() > 1) - i_to_k = "(" + j_to_i + ")"; + else + continue; + i_to_k = "(" + i_to_k + ")"; + new_transitions[j][k].insert(j_to_i + loop + i_to_k); } @@ -96,7 +99,7 @@ std::string DFAGraphToRegular(DFAGraph&& graph) { } std::string loop; - std::string begin_to_end; + std::string start_to_end; if (transitions[1][1].size() != 0) { for (const std::string& s: transitions[1][1]) { @@ -105,20 +108,22 @@ std::string DFAGraphToRegular(DFAGraph&& graph) { loop += ")"; loop += "|"; } - if (loop.size()) + if (loop.size()) { loop.pop_back(); - loop = "(" + loop + ")*"; + loop = "(" + loop + ")*"; + } else { + loop = ""; + } } for (const std::string& s: transitions[1][0]) { - begin_to_end += "("; - begin_to_end += s; - begin_to_end += ")"; - begin_to_end += "|"; + start_to_end += "("; + start_to_end += s; + start_to_end += ")"; + start_to_end += "|"; } - if (begin_to_end.size()) - begin_to_end.pop_back(); + if (start_to_end.size()) + start_to_end.pop_back(); - std::string res(loop + "(" + begin_to_end + ")"); - return res; + return loop + "(" + start_to_end + ")"; } } diff --git a/src/main.cpp b/src/main.cpp index 9187628..b7be29e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,11 @@ #include "converters/DFAToMinDFA.hpp" #include "converters/DFAToRegular.hpp" #include "converters/InvertFDFA.hpp" +#include + +#define RegularStringToDFAGraph(s) NFAGraphToDFAGraph(RegularToNFAGraph(RegularTree(s))) +#define RegularStringToMinDFAGraph(s) DFAGraphToMinDFAGraph(NFAGraphToDFAGraph(RegularToNFAGraph(RegularTree(s)))) +#define InvertRegularString(v, s) RegularTree(DFAGraphToRegular(DFAGraphToMinDFAGraph(InvertFDFAGraph(DFAGraphToMinDFAGraph(DFAGraphToFDFAGraph(NFAGraphToDFAGraph(RegularToNFAGraph(RegularTree(s))), v)))))).ToString() using namespace regular; using namespace NFA; @@ -49,60 +54,15 @@ void example2() { dfa_graph.Print(); } -int main() { - { - RegularTree r("a*"); - NFAGraph NFA_graph = RegularToNFAGraph(std::move(r)); - DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_graph)); - DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); - DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b'}); - DFA_graph.Print(); - DFA_graph.CreateDotFile("1.dot"); - DFA_graph = InvertFDFAGraph(std::move(DFA_graph)); - DFA_graph.CreateDotFile("2.dot"); - DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); +std::mt19937 rnd(1337); + +std::string GenerateRandomString(std::vector alphabet, size_t len) { + std::string res(len, ' '); + for (auto& i: res) { + i = alphabet[rnd() % alphabet.size()]; } - - return 0; - { - RegularTree r("((ab|ba)*( |a|ba))"); - NFAGraph NFA_tree = RegularToNFAGraph(std::move(r)); - DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); - // DFA_graph.CreateDotFile("1.dot"); - // DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); - DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b'}); - DFA_graph = InvertFDFAGraph(std::move(DFA_graph)); - // DFA_graph.CreateDotFile("2.dot"); - auto ss = DFAGraphToRegular(std::move(DFA_graph)); - std::cout << ss << std::endl; - r = RegularTree(ss); - // r.Print(); - std::cout << r.ToString() << std::endl; - // DFA_graph.Print(); - return 0; - - DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); - DFA_graph.Print(); - auto s = DFAGraphToRegular(std::move(DFA_graph)); - std::cout << s << std::endl; - r = RegularTree(s); - // r.Print(); - std::cout << r.ToString() << std::endl; - } - return 0; - RegularTree r("a*"); - auto nfa = RegularToNFAGraph(std::move(r)); - auto dfa = NFAGraphToDFAGraph(std::move(nfa)); - dfa = DFAGraphToMinDFAGraph(std::move(dfa)); - auto fdfa = DFAGraphToFDFAGraph(std::move(dfa), {'a', 'b'}); - fdfa.Print(); - fdfa = InvertFDFAGraph(std::move(fdfa)); - fdfa.Print(); - dfa = DFAGraphToMinDFAGraph(std::move(fdfa)); - auto s = DFAGraphToRegular(std::move(dfa)); - - /* - RegularTree r("(a|b)+bab(a|b)+"); - std::cout << DFAGraphToRegular(DFAGraphToMinDFAGraph(InvertFDFAGraph(DFAGraphToFDFAGraph(DFAGraphToMinDFAGraph(NFAGraphToDFAGraph(RegularToNFAGraph(std::move(r)))), {'a', 'b'})))) << std::endl; - */ + return res; +} + +int main() { } diff --git a/tests/GenericTest/GenericTest1.cpp b/tests/GenericTest/GenericTest1.cpp new file mode 100644 index 0000000..c88adc9 --- /dev/null +++ b/tests/GenericTest/GenericTest1.cpp @@ -0,0 +1,69 @@ +#include +#include +#include "regular/RegularTree.hpp" +#include "converters/RegularToNFA.hpp" +#include "converters/NFAToDFA.hpp" +#include "converters/DFAToMinDFA.hpp" +#include "converters/DFAToFDFA.hpp" +#include "converters/InvertFDFA.hpp" +#include "converters/DFAToRegular.hpp" + +using namespace regular; +using namespace NFA; +using namespace DFA; +using namespace converters; + +extern std::mt19937 rnd; + +extern std::string GenerateRandomString(std::vector alphabet, size_t len); + +TEST(generic_tests, divided_5) { + DFAGraph DFA_graph; + size_t a[10]; + for (int i = 0; i < 10; ++i) { + a[i] = DFA_graph.AddNewVertex(); + } + auto add_edge = [&DFA_graph, &a](size_t in, size_t out, char x) { + DFA_graph.GetVertex(a[in]).AddEdge(x, a[out]); + }; + add_edge(5, 6, '0'); + add_edge(5, 1, '1'); + add_edge(1, 2, '0'); + add_edge(1, 3, '1'); + add_edge(2, 4, '0'); + add_edge(2, 0, '1'); + add_edge(3, 1, '0'); + add_edge(3, 2, '1'); + add_edge(4, 3, '0'); + add_edge(4, 4, '1'); + add_edge(0, 0, '0'); + add_edge(0, 1, '1'); + DFA_graph.GetVertex(a[5]).SetStart(true); + DFA_graph.GetVertex(a[6]).SetFinal(true); + DFA_graph.GetVertex(a[0]).SetFinal(true); + + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + DFA_graph = NFAGraphToDFAGraph(RegularToNFAGraph(RegularTree(DFAGraphToRegular(std::move(DFA_graph))))); + + auto check = [](const std::string& str) -> bool { + bool answer = true; + if (str.size() == 1) { + return str == "0"; + } + if (str[0] == '0') { + return false; + } + int remainder = 0; + for (auto i: str) { + remainder = remainder * 2 + i - '0'; + remainder %= 5; + } + return remainder == 0; + }; + + for (int i = 0; i < 2000; ++i) { + std::string test = GenerateRandomString({'0', '1'}, rnd() % 1000 + 1); + + ASSERT_EQ(DFA_graph.Accepted(test), check(test)); + } +}