diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ebfd89..bd98941 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,8 +18,8 @@ set(CMAKE_CXX_STANDARD 17) set(SOURCE_FILES src/regular/RegularTree.cpp src/regular/RegularTreeNode.cpp - src/NFA/NFAGraph.cpp - src/NFA/NFATreeVertex.cpp + src/NFA/NFAGraph.cpp + src/NFA/NFAGraphVertex.cpp src/converters/RegularToNFA.cpp src/converters/NFAToDFA.cpp src/DFA/DFAGraph.cpp @@ -27,18 +27,20 @@ set(SOURCE_FILES src/converters/DFAToFDFA.cpp src/converters/DFAToMinDFA.cpp src/converters/DFAToRegular.cpp + src/converters/InvertFDFA.cpp ) set(TEST_FILES - tests/regular/parse_regular.cpp - tests/NFAToDFA/check_equivalence.cpp - tests/regularToDFA/regularToDFA.cpp + tests/regular/ParseRegular.cpp + tests/NFAToDFA/CheckEquivalence.cpp + tests/regularToDFA/RegularToDFA.cpp tests/DFAToRegular/DFAToRegular.cpp + tests/invertFDFA/InvertFDFA.cpp ) add_executable(Formalang src/main.cpp ${SOURCE_FILES}) -add_executable(Tests tests/test_main.cpp ${TEST_FILES} ${SOURCE_FILES}) +add_executable(Tests tests/MainTest.cpp ${TEST_FILES} ${SOURCE_FILES}) target_link_libraries(Tests ${GTEST_LIBRARIES} Threads::Threads) target_link_libraries(Formalang Threads::Threads) diff --git a/include/DFA/DFAGraph.hpp b/include/DFA/DFAGraph.hpp index af1f100..a04c796 100644 --- a/include/DFA/DFAGraph.hpp +++ b/include/DFA/DFAGraph.hpp @@ -38,10 +38,10 @@ class DFAGraph { DFAGraph() = default; DFAGraph(const DFAGraph&) = delete; - DFAGraph(DFAGraph&&) = default; + DFAGraph(DFAGraph&&); DFAGraph& operator=(const DFAGraph&) = delete; - DFAGraph& operator=(DFAGraph&&) = default; + DFAGraph& operator=(DFAGraph&&); size_t AddNewVertex(); void AddFinalVertex(size_t number); diff --git a/include/converters/InvertFDFA.hpp b/include/converters/InvertFDFA.hpp new file mode 100644 index 0000000..e5dce0e --- /dev/null +++ b/include/converters/InvertFDFA.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "DFA/DFAGraph.hpp" + +namespace converters { +using namespace DFA; +DFAGraph InvertFDFAGraph(DFAGraph&&); +} diff --git a/src/DFA/DFAGraph.cpp b/src/DFA/DFAGraph.cpp index 01882a3..90f8c40 100644 --- a/src/DFA/DFAGraph.cpp +++ b/src/DFA/DFAGraph.cpp @@ -3,6 +3,30 @@ #include namespace DFA { +DFAGraph::DFAGraph(DFAGraph&& another) { + std::swap(count_vertexes_, another.count_vertexes_); + std::swap(vertexes_, another.vertexes_); + std::swap(final_vertexes_, another.final_vertexes_); + std::swap(start_vertexes_, another.start_vertexes_); + + for (auto& i: vertexes_) + i.second->owner_ = this; + for (auto& i: another.vertexes_) + i.second->owner_ = &another; +} + +DFAGraph& DFAGraph::operator=(DFAGraph&& another) { + std::swap(count_vertexes_, another.count_vertexes_); + std::swap(vertexes_, another.vertexes_); + std::swap(final_vertexes_, another.final_vertexes_); + std::swap(start_vertexes_, another.start_vertexes_); + + for (auto& i: vertexes_) + i.second->owner_ = this; + for (auto& i: another.vertexes_) + i.second->owner_ = &another; + return *this; +} size_t DFAGraph::AddNewVertex() { vertexes_[count_vertexes_] = std::make_shared(this); vertexes_[count_vertexes_]->number_ = count_vertexes_; diff --git a/src/NFA/NFATreeVertex.cpp b/src/NFA/NFAGraphVertex.cpp similarity index 100% rename from src/NFA/NFATreeVertex.cpp rename to src/NFA/NFAGraphVertex.cpp diff --git a/src/converters/InvertFDFA.cpp b/src/converters/InvertFDFA.cpp new file mode 100644 index 0000000..4d3c5e0 --- /dev/null +++ b/src/converters/InvertFDFA.cpp @@ -0,0 +1,12 @@ +#include "converters/InvertFDFA.hpp" + +namespace converters { +DFAGraph InvertFDFAGraph(DFAGraph&& fdfa_graph) { + const size_t n = fdfa_graph.GetCountVertexes(); + for (int i = 0; i < n; ++i) { + if (!fdfa_graph.GetVertex(i)) continue; + fdfa_graph.GetVertex(i)->SetFinal(!fdfa_graph.GetVertex(i)->IsFinal()); + } + return std::move(fdfa_graph); +} +} diff --git a/src/main.cpp b/src/main.cpp index 1b71cd0..1792d0f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ #include "converters/DFAToFDFA.hpp" #include "converters/DFAToMinDFA.hpp" #include "converters/DFAToRegular.hpp" +#include "converters/InvertFDFA.hpp" using namespace regular; using namespace regular; @@ -13,161 +14,66 @@ using namespace NFA; using namespace DFA; using namespace converters; +void example1() { + RegularTree r("a*"); + NFAGraph NFA_tree = RegularToNFAGraph(std::move(r)); // Regular to FA + DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); // to DFA + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); // minimize + std::string reg = DFAGraphToRegular(std::move(DFA_graph)); // DFA to regular + r = RegularTree(reg); // create regular + NFA_tree = RegularToNFAGraph(std::move(r)); // to FA + DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); // to DFA + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); // minimize + DFA_graph.Print(); // print +} + +void example2() { + NFAGraph nfa_graph; + const size_t N = 10; + + size_t a[N]; + for (size_t i = 0; i < N; ++i) + a[i] = nfa_graph.AddNewVertex(); + + auto AddEdge = [&nfa_graph, &a](char symbol, int u, int v) { + nfa_graph.GetVertex(a[u])->AddEdge(symbol, a[v]); + }; + + AddEdge('a', 0, 1); + AddEdge('b', 0, 2); + AddEdge('b', 1, 3); + AddEdge('b', 2, 4); + + DFAGraph dfa_graph = NFAGraphToDFAGraph(std::move(nfa_graph)); + dfa_graph = DFAGraphToMinDFAGraph(std::move(dfa_graph)); + dfa_graph.Print(); +} + int main() { { RegularTree r("a*"); NFAGraph NFA_tree = RegularToNFAGraph(std::move(r)); DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'}); DFA_graph.Print(); - - std::string reg = DFAGraphToRegular(std::move(DFA_graph)); - - r = RegularTree(reg); - NFA_tree = RegularToNFAGraph(std::move(r)); - DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); + DFA_graph = InvertFDFAGraph(std::move(DFA_graph)); + return 0; DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); - DFA_graph.Print(); } - 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+"); - r.Print(); - NFA::NFAGraph NFA_tree = converters::RegularToNFAGraph(std::move(r)); - NFA_tree.Print(); - DFA::DFAGraph DFA_graph = converters::NFAGraphToDFAGraph(std::move(NFA_tree)); - DFA_graph.Print(); - DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); - DFA_graph.Print(); - } - - return 0; - NFA::NFAGraph tree; - - const int N = 10; - int a[N]; - for (int i = 0; i < N; ++i) - a[i] = tree.AddNewVertex(); - - /* - tree.GetVertex(a[1])->AddEdge('a', a[1]); - tree.GetVertex(a[1])->AddEdge('b', a[1]); - tree.GetVertex(a[1])->AddEdge('a', a[2]); - tree.GetVertex(a[1])->AddEdge('a', a[8]); - tree.GetVertex(a[2])->AddEdge('b', a[3]); - tree.GetVertex(a[3])->AddEdge('a', a[4]); - tree.GetVertex(a[4])->AddEdge('b', a[4]); - tree.GetVertex(a[4])->AddEdge('a', a[7]); - tree.GetVertex(a[7])->AddEdge('b', a[7]); - tree.GetVertex(a[8])->AddEdge('a', a[6]); - tree.GetVertex(a[6])->AddEdge('a', a[6]); - tree.GetVertex(a[6])->AddEdge('b', a[6]); - tree.GetVertex(a[6])->AddEdge('b', a[5]); - tree.GetVertex(a[5])->AddEdge('b', a[4]); - - tree.GetVertex(a[1])->SetStart(true); - tree.GetVertex(a[7])->SetFinal(true); - */ - - /* - tree.GetVertex(a[0])->AddEdge('a', a[1]); - tree.GetVertex(a[1])->AddEdge('a', a[2]); - tree.GetVertex(a[2])->AddEdge('a', a[3]); - tree.GetVertex(a[3])->AddEdge('b', a[4]); - tree.GetVertex(a[4])->AddEdge('a', a[5]); - tree.GetVertex(a[5])->AddEdge('a', a[6]); - tree.GetVertex(a[6])->AddEdge('b', a[7]); - tree.GetVertex(a[2])->AddEdge(' ', a[4]); - tree.GetVertex(a[4])->AddEdge(' ', a[2]); - tree.GetVertex(a[5])->AddEdge(' ', a[7]); - tree.GetVertex(a[7])->AddEdge(' ', a[5]); - tree.GetVertex(a[7])->AddEdge(' ', a[1]); - tree.GetVertex(a[1])->AddEdge('b', a[1]); - - tree.GetVertex(a[0])->SetStart(true); - tree.GetVertex(a[1])->SetFinal(true); - */ - /* - tree.GetVertex(a[0])->AddEdge('a', a[1]); - tree.GetVertex(a[0])->AddEdge('a', a[2]); - tree.GetVertex(a[1])->AddEdge('b', a[1]); - tree.GetVertex(a[2])->AddEdge('c', a[2]); - tree.GetVertex(a[0])->SetStart(true); - tree.GetVertex(a[1])->SetFinal(true); - tree.GetVertex(a[2])->SetFinal(true); - */ - - tree.GetVertex(a[0])->AddEdge('a', a[1]); - tree.GetVertex(a[0])->AddEdge('b', a[2]); - - tree.GetVertex(a[1])->AddEdge('b', a[3]); - tree.GetVertex(a[2])->AddEdge('b', a[4]); - - tree.GetVertex(a[0])->SetStart(true); - tree.GetVertex(a[3])->SetFinal(true); - tree.GetVertex(a[4])->SetFinal(true); - - DFA::DFAGraph res = converters::NFAGraphToDFAGraph(std::move(tree)); - // FDFA::FDFAGraph res2 = converters::DFAGraphToFDFAGraph(std::move(res), {'a', 'b'}); - - // res2.Print(); - - // std::cout << "\n#####################\n\n"; - - // res = converters::DFAGraphToFDFAGraph(std::move(res), {'a', 'b'}); - - res = converters::DFAGraphToMinDFAGraph(std::move(res)); - - res.Print(); - - std::string reg = converters::DFAGraphToRegular(std::move(res)); - - std::cout << reg << std::endl; - - - /* - tree = converters::AddAllEpsilonTransitions(std::move(tree)); - - tree.Print(); - - std::cout << "\n#####################\n\n"; - - tree = converters::DeleteEpsilonTransitions(std::move(tree)); - - tree.Print(); - - std::cout << "\n#####################\n\n"; - - tree = converters::DeleteTransitionsByOneLetter(std::move(tree)); - - tree.Print(); - - std::cout << "\n#####################\n\n"; - */ - - /* - DFA::DFAGraph res = converters::NFATreeToDFAGraph(std::move(tree)); - - res.Print(); - */ - std::cout << "END" << std::endl; - - return 0; - - - std::string str; - std::cin >> str; - RegularTree reg_tree(str); - reg_tree.Print(); - - auto NFA_tree = converters::RegularToNFAGraph(std::move(reg_tree)); - - std::cout << std::endl; - - NFA_tree.Print(); - - + // RegularTree r("(a|b)+bab(a|b)+"); + // std::cout << DFAGraphToRegular(DFAGraphToMinDFAGraph(InvertFDFAGraph(DFAGraphToFDFAGraph(DFAGraphToMinDFAGraph(NFAGraphToDFAGraph(RegularToNFAGraph(std::move(r)))), {'a', 'b'})))) << std::endl; } diff --git a/tests/test_main.cpp b/tests/MainTest.cpp similarity index 100% rename from tests/test_main.cpp rename to tests/MainTest.cpp diff --git a/tests/NFAToDFA/check_equivalence.cpp b/tests/NFAToDFA/CheckEquivalence.cpp similarity index 100% rename from tests/NFAToDFA/check_equivalence.cpp rename to tests/NFAToDFA/CheckEquivalence.cpp diff --git a/tests/invertFDFA/InvertFDFA.cpp b/tests/invertFDFA/InvertFDFA.cpp new file mode 100644 index 0000000..cc1efb2 --- /dev/null +++ b/tests/invertFDFA/InvertFDFA.cpp @@ -0,0 +1,181 @@ +#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" + +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(invert_DFA, a_star) { + RegularTree r("a*"); + NFAGraph NFA_tree = RegularToNFAGraph(std::move(r)); + DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'}); + DFA_graph = InvertFDFAGraph(std::move(DFA_graph)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + std::string s = ""; + for (int i = 0; i < 100; ++i) { + ASSERT_EQ(DFA_graph.Accepted(s), false); + s += "a"; + } +} + +TEST(invert_DFA, a_plus) { + std::string regulars[] = {"a+", "(a)+", "(a+)"}; + for (const auto& regular: regulars) { + RegularTree r(regular); + NFAGraph NFA_tree = RegularToNFAGraph(std::move(r)); + DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'}); + DFA_graph = InvertFDFAGraph(std::move(DFA_graph)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + std::string s = ""; + ASSERT_EQ(DFA_graph.Accepted(s), true); + s += "a"; + for (int i = 0; i < 100; ++i) { + ASSERT_EQ(DFA_graph.Accepted(s), false); + s += "a"; + } + } +} + +TEST(invert_DFA, abc) { + std::string regulars[] = {"abc"}; + for (const auto& regular: regulars) { + RegularTree r(regular); + NFAGraph NFA_tree = RegularToNFAGraph(std::move(r)); + DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'}); + DFA_graph = InvertFDFAGraph(std::move(DFA_graph)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + ASSERT_EQ(DFA_graph.Accepted("abc"), false); + for (int i = 0; i < 1000; ++i) { + auto s = GenerateRandomString({'a', 'b', 'c', 'd'}, rnd() % 10); + if (s == "abc") continue; + ASSERT_EQ(DFA_graph.Accepted(s), true); + } + } +} + +TEST(invert_DFA, a_or_b_or_c) { + std::string regulars[] = {}; + for (const auto& regular: regulars) { + RegularTree r("a|b|c"); + NFAGraph NFA_tree = RegularToNFAGraph(std::move(r)); + DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'}); + DFA_graph = InvertFDFAGraph(std::move(DFA_graph)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + ASSERT_EQ(DFA_graph.Accepted("a"), false); + ASSERT_EQ(DFA_graph.Accepted("b"), false); + ASSERT_EQ(DFA_graph.Accepted("c"), false); + for (int i = 0; i < 1000; ++i) { + auto s = GenerateRandomString({'a', 'b', 'c', 'd'}, rnd() % 10); + if (s == "a") continue; + if (s == "b") continue; + if (s == "c") continue; + ASSERT_EQ(DFA_graph.Accepted(s), true); + } + } +} + +TEST(invert_DFA, a_star_or_b_star_or_c_star) { + std::string regulars[] = {"a*|b*|c*", "(a*)|(b*|c*)", "(a*|b*|c*)", "((a*)|(b*)|(c*))"}; + for (const auto& regular: regulars) { + RegularTree r(regular); + NFAGraph NFA_tree = RegularToNFAGraph(std::move(r)); + DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'}); + DFA_graph = InvertFDFAGraph(std::move(DFA_graph)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + auto check = [](const std::string str) { + std::set s(str.begin(), str.end()); + if (s.size() == 0) + return true; + else { + if (s.size() == 1) + return *s.begin() != 'd'; + else + return false; + } + }; + + ASSERT_EQ(DFA_graph.Accepted(""), false); + for (int i = 0; i < 1000; ++i) { + auto s = GenerateRandomString({'a', 'b', 'c', 'd'}, rnd() % 10); + + ASSERT_EQ(DFA_graph.Accepted(s), !check(s)); + } + } +} + +TEST(invert_DFA, _a_star_or_b_star_or_c_star_plus) { + RegularTree r("(a*|b*|c*)+"); + NFAGraph NFA_tree = RegularToNFAGraph(std::move(r)); + DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'}); + DFA_graph = InvertFDFAGraph(std::move(DFA_graph)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + auto check = [](const std::string str) { + std::set s(str.begin(), str.end()); + return s.find('d') == s.end(); + }; + + ASSERT_EQ(DFA_graph.Accepted(""), false); + for (int i = 0; i < 1000; ++i) { + auto s = GenerateRandomString({'a', 'b', 'c', 'd'}, rnd() % 10); + + ASSERT_EQ(DFA_graph.Accepted(s), !check(s)); + } +} + +TEST(invert_DFA, _a_or_b_or_c_star_plus) { + RegularTree r("(a|b|c*)+"); + NFAGraph NFA_tree = RegularToNFAGraph(std::move(r)); + DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'}); + DFA_graph = InvertFDFAGraph(std::move(DFA_graph)); + DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); + + auto check = [](const std::string str) { + std::set s(str.begin(), str.end()); + return s.find('d') == s.end(); + }; + + ASSERT_EQ(DFA_graph.Accepted(""), false); + for (int i = 0; i < 1000; ++i) { + auto s = GenerateRandomString({'a', 'b', 'c', 'd'}, rnd() % 10); + + ASSERT_EQ(DFA_graph.Accepted(s), !check(s)); + } +} diff --git a/tests/regular/parse_regular.cpp b/tests/regular/ParseRegular.cpp similarity index 100% rename from tests/regular/parse_regular.cpp rename to tests/regular/ParseRegular.cpp diff --git a/tests/regularToDFA/regularToDFA.cpp b/tests/regularToDFA/RegularToDFA.cpp similarity index 100% rename from tests/regularToDFA/regularToDFA.cpp rename to tests/regularToDFA/RegularToDFA.cpp