From 32f8a3dcc6df5f8b2d347aae4ca1bb128027e76d Mon Sep 17 00:00:00 2001 From: MaxanRus Date: Tue, 5 Oct 2021 15:01:30 +0300 Subject: [PATCH] Many changes --- CMakeLists.txt | 11 + include/DFA/DFAGraph.hpp | 68 +++++++ include/FDFA/FDFAGraph.hpp | 67 ++++++ include/NFA/NFATree.hpp | 19 +- include/converters/DFAToFDFA.hpp | 10 + include/converters/DFAToMinDFA.hpp | 7 + include/converters/DFAToRegular.hpp | 8 + include/converters/NFAToDFA.hpp | 13 ++ include/converters/RegularToNFA.hpp | 10 + src/DFA/DFAGraph.cpp | 98 +++++++++ src/DFA/DFAGraphVertex.cpp | 58 ++++++ src/FDFA/FDFAGraph.cpp | 98 +++++++++ src/FDFA/FDFAGraphVertex.cpp | 58 ++++++ src/NFA/NFATree.cpp | 59 +++++- src/NFA/NFATreeVertex.cpp | 50 ++++- src/converters/DFAToFDFA.cpp | 90 ++++++++ src/converters/DFAToMinDFA.cpp | 111 ++++++++++ src/converters/DFAToRegular.cpp | 126 ++++++++++++ src/converters/NFAToDFA.cpp | 293 +++++++++++++++++++++++++++ src/converters/RegularToNFA.cpp | 50 ++++- src/main.cpp | 156 +++++++++++++- src/regular/RegularTreeNode.cpp | 22 +- tests/DFAToRegular/DFAToRegular.cpp | 202 ++++++++++++++++++ tests/NFAToDFA/check_equivalence.cpp | 111 ++++++++++ tests/regularToDFA/regularToDFA.cpp | 151 ++++++++++++++ 25 files changed, 1917 insertions(+), 29 deletions(-) create mode 100644 include/DFA/DFAGraph.hpp create mode 100644 include/FDFA/FDFAGraph.hpp create mode 100644 include/converters/DFAToFDFA.hpp create mode 100644 include/converters/DFAToMinDFA.hpp create mode 100644 include/converters/DFAToRegular.hpp create mode 100644 include/converters/NFAToDFA.hpp create mode 100644 include/converters/RegularToNFA.hpp create mode 100644 src/DFA/DFAGraph.cpp create mode 100644 src/DFA/DFAGraphVertex.cpp create mode 100644 src/FDFA/FDFAGraph.cpp create mode 100644 src/FDFA/FDFAGraphVertex.cpp create mode 100644 src/converters/DFAToFDFA.cpp create mode 100644 src/converters/DFAToMinDFA.cpp create mode 100644 src/converters/DFAToRegular.cpp create mode 100644 src/converters/NFAToDFA.cpp create mode 100644 tests/DFAToRegular/DFAToRegular.cpp create mode 100644 tests/NFAToDFA/check_equivalence.cpp create mode 100644 tests/regularToDFA/regularToDFA.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3edb7f2..21991db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,10 +21,21 @@ set(SOURCE_FILES src/NFA/NFATree.cpp src/NFA/NFATreeVertex.cpp src/converters/RegularToNFA.cpp + src/converters/NFAToDFA.cpp + src/DFA/DFAGraph.cpp + src/DFA/DFAGraphVertex.cpp + # src/FDFA/FDFAGraph.cpp + # src/FDFA/FDFAGraphVertex.cpp + src/converters/DFAToFDFA.cpp + src/converters/DFAToMinDFA.cpp + src/converters/DFAToRegular.cpp ) set(TEST_FILES tests/regular/parse_regular.cpp + tests/NFAToDFA/check_equivalence.cpp + tests/regularToDFA/regularToDFA.cpp + tests/DFAToRegular/DFAToRegular.cpp ) add_executable(Formalang src/main.cpp ${SOURCE_FILES}) diff --git a/include/DFA/DFAGraph.hpp b/include/DFA/DFAGraph.hpp new file mode 100644 index 0000000..af1f100 --- /dev/null +++ b/include/DFA/DFAGraph.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include +#include + +namespace DFA { +class DFAGraph { + public: + class Vertex { + public: + Vertex(DFAGraph* owner); + + bool IsFinal() const; + bool IsStart() const; + size_t GetNumber() const; + + const std::map& GetTransitions() const; + const std::map& GetBackTransitions() const; + + void AddEdge(char, size_t); + void RemoveEdge(char); + void SetOwner(DFAGraph* owner); + void SetFinal(bool status); + void SetStart(bool status); + private: + DFAGraph* owner_; + std::map transitions_; + std::map back_transitions_; + + size_t number_; + bool is_final_ = false; + bool is_start_ = false; + + friend class DFAGraph; + }; + + DFAGraph() = default; + DFAGraph(const DFAGraph&) = delete; + DFAGraph(DFAGraph&&) = default; + + DFAGraph& operator=(const DFAGraph&) = delete; + DFAGraph& operator=(DFAGraph&&) = default; + + size_t AddNewVertex(); + void AddFinalVertex(size_t number); + void AddStartVertex(size_t number); + + void RemoveVertex(size_t number); + void RemoveFinalVertex(size_t number); + void RemoveStartVertex(size_t number); + + std::shared_ptr GetVertex(size_t number); + + size_t GetCountVertexes() const; + const std::vector& GetFinalVertexes() const; + const std::vector& GetStartVertexes() const; + + void Print() const; + bool Accepted(const std::string&) const; + private: + size_t count_vertexes_ = 0; + std::map> vertexes_; + std::vector final_vertexes_; + std::vector start_vertexes_; +}; +} diff --git a/include/FDFA/FDFAGraph.hpp b/include/FDFA/FDFAGraph.hpp new file mode 100644 index 0000000..591a50f --- /dev/null +++ b/include/FDFA/FDFAGraph.hpp @@ -0,0 +1,67 @@ +#pragma once +#include +#include +#include +#include + +namespace FDFA { +class FDFAGraph { + public: + class Vertex { + public: + Vertex(FDFAGraph* owner); + + bool IsFinal() const; + bool IsStart() const; + size_t GetNumber() const; + + const std::map& GetTransitions() const; + const std::map& GetBackTransitions() const; + + void AddEdge(char, size_t); + void RemoveEdge(char); + void SetOwner(FDFAGraph* owner); + void SetFinal(bool status); + void SetStart(bool status); + private: + FDFAGraph* owner_; + std::map transitions_; + std::map back_transitions_; + + size_t number_; + bool is_final_ = false; + bool is_start_ = false; + + friend class FDFAGraph; + }; + + FDFAGraph() = default; + FDFAGraph(const FDFAGraph&) = delete; + FDFAGraph(FDFAGraph&&) = default; + + FDFAGraph& operator=(const FDFAGraph&) = delete; + FDFAGraph& operator=(FDFAGraph&&) = default; + + size_t AddNewVertex(); + void AddFinalVertex(size_t number); + void AddStartVertex(size_t number); + + void RemoveVertex(size_t number); + void RemoveFinalVertex(size_t number); + void RemoveStartVertex(size_t number); + + std::shared_ptr GetVertex(size_t number); + + size_t GetCountVertexes() const; + const std::vector& GetFinalVertexes() const; + const std::vector& GetStartVertexes() const; + + void Print() const; + bool Accepted(const std::string&) const; + private: + size_t count_vertexes_ = 0; + std::map> vertexes_; + std::vector final_vertexes_; + std::vector start_vertexes_; +}; +} diff --git a/include/NFA/NFATree.hpp b/include/NFA/NFATree.hpp index d67a199..02e0d56 100644 --- a/include/NFA/NFATree.hpp +++ b/include/NFA/NFATree.hpp @@ -10,15 +10,24 @@ class NFATree { public: class Vertex { public: - Vertex(); + Vertex(NFATree* owner); bool IsFinal() const; bool IsStart() const; size_t GetNumber() const; - std::multimap transitions; + const std::map>& GetTransitions() const; + const std::map>& GetBackTransitions() const; + + void AddEdge(char, size_t); + void RemoveEdge(char, size_t); + void SetOwner(NFATree* owner); + void SetFinal(bool status); + void SetStart(bool status); private: - Vertex(bool is_final, bool is_start); + NFATree* owner_; + std::map> transitions_; + std::map> back_transitions_; size_t number_; bool is_final_ = false; @@ -29,10 +38,10 @@ class NFATree { NFATree() = default; NFATree(const NFATree&) = delete; - NFATree(NFATree&&) = default; + NFATree(NFATree&&); NFATree& operator=(const NFATree&) = delete; - NFATree& operator=(NFATree&&) = default; + NFATree& operator=(NFATree&&); size_t AddNewVertex(); void AddFinalVertex(size_t number); diff --git a/include/converters/DFAToFDFA.hpp b/include/converters/DFAToFDFA.hpp new file mode 100644 index 0000000..bdf1eda --- /dev/null +++ b/include/converters/DFAToFDFA.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "DFA/DFAGraph.hpp" +#include "FDFA/FDFAGraph.hpp" + +namespace converters { +using namespace DFA; +using namespace FDFA; +DFAGraph DFAGraphToFDFAGraph(DFAGraph&&, const std::vector& alphabet); +// FDFAGraph DFAGraphToFDFAGraph(DFAGraph&&, const std::vector& alphabet); +} diff --git a/include/converters/DFAToMinDFA.hpp b/include/converters/DFAToMinDFA.hpp new file mode 100644 index 0000000..dd25402 --- /dev/null +++ b/include/converters/DFAToMinDFA.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "DFA/DFAGraph.hpp" + +namespace converters { +using namespace DFA; +DFAGraph DFAToMinDFA(DFAGraph&&); +} diff --git a/include/converters/DFAToRegular.hpp b/include/converters/DFAToRegular.hpp new file mode 100644 index 0000000..4c825da --- /dev/null +++ b/include/converters/DFAToRegular.hpp @@ -0,0 +1,8 @@ +#pragma once +#include "DFA/DFAGraph.hpp" +#include + +namespace converters { +using namespace DFA; +std::string DFAGraphToRegular(DFAGraph&&); +} diff --git a/include/converters/NFAToDFA.hpp b/include/converters/NFAToDFA.hpp new file mode 100644 index 0000000..ecb0669 --- /dev/null +++ b/include/converters/NFAToDFA.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "NFA/NFATree.hpp" +#include "DFA/DFAGraph.hpp" + +namespace converters { +using namespace NFA; +using namespace DFA; +NFATree AddAllEpsilonTransitions(NFATree&&); +NFATree AddAllPossibleStartFilnal(NFATree&&); +NFATree DeleteEpsilonTransitions(NFATree&&); +NFATree DeleteTransitionsByOneLetter(NFATree&&); +DFAGraph NFATreeToDFAGraph(NFATree&&); +} diff --git a/include/converters/RegularToNFA.hpp b/include/converters/RegularToNFA.hpp new file mode 100644 index 0000000..d4dd5f9 --- /dev/null +++ b/include/converters/RegularToNFA.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "regular/RegularTree.hpp" +#include "NFA/NFATree.hpp" + +namespace converters { +using namespace NFA; +using namespace regular; + +NFATree RegularToNFA(RegularTree&&); +} diff --git a/src/DFA/DFAGraph.cpp b/src/DFA/DFAGraph.cpp new file mode 100644 index 0000000..01882a3 --- /dev/null +++ b/src/DFA/DFAGraph.cpp @@ -0,0 +1,98 @@ +#include "DFA/DFAGraph.hpp" +#include +#include + +namespace DFA { +size_t DFAGraph::AddNewVertex() { + vertexes_[count_vertexes_] = std::make_shared(this); + vertexes_[count_vertexes_]->number_ = count_vertexes_; + return count_vertexes_++; +} + +void DFAGraph::AddFinalVertex(size_t number) { + if (!vertexes_[number]->is_final_) { + vertexes_[number]->is_final_ = true; + final_vertexes_.push_back(number); + } +} + +void DFAGraph::AddStartVertex(size_t number) { + if (!vertexes_[number]->is_start_) { + vertexes_[number]->is_start_ = true; + start_vertexes_.push_back(number); + } +} + +void DFAGraph::RemoveVertex(size_t number) { + RemoveFinalVertex(number); + RemoveStartVertex(number); + vertexes_.erase(number); +} + +void DFAGraph::RemoveFinalVertex(size_t number) { + for (size_t i = 0; i < final_vertexes_.size(); ++i) { + if (final_vertexes_[i] == number) { + vertexes_[number]->is_final_ = false; + std::swap(final_vertexes_[i], final_vertexes_.back()); + final_vertexes_.pop_back(); + break; + } + } +} + +void DFAGraph::RemoveStartVertex(size_t number) { + for (size_t i = 0; i < start_vertexes_.size(); ++i) { + if (start_vertexes_[i] == number) { + vertexes_[number]->is_start_ = false; + std::swap(start_vertexes_[i], start_vertexes_.back()); + start_vertexes_.pop_back(); + break; + } + } +} + +std::shared_ptr DFAGraph::GetVertex(size_t number) { + if (vertexes_.count(number)) + return vertexes_[number]; + return nullptr; +} + +size_t DFAGraph::GetCountVertexes() const { + return count_vertexes_; +} + +const std::vector& DFAGraph::GetFinalVertexes() const { + return final_vertexes_; +} + +const std::vector& DFAGraph::GetStartVertexes() const { + return start_vertexes_; +} + +void DFAGraph::Print() const { + for (auto i: vertexes_) { + std::cout << i.second->number_ << " " << "f-" << i.second->is_final_ << " s-" << + i.second->is_start_ << std::endl; + } + for (auto& i: vertexes_) { + for (auto& j: i.second->transitions_) { + std::cout << i.second->number_ << "->" << j.second << " <" << j.first << ">" << + std::endl; + } + } + std::cout << std::endl; +} + +bool DFAGraph::Accepted(const std::string& str) const { + std::shared_ptr current = vertexes_.at(start_vertexes_[0]); + for (auto i: str) { + if (current->GetTransitions().count(i)) { + current = vertexes_.at(current->GetTransitions().at(i)); + } else { + return false; + } + } + return current->IsFinal(); +} +} + diff --git a/src/DFA/DFAGraphVertex.cpp b/src/DFA/DFAGraphVertex.cpp new file mode 100644 index 0000000..a5d0f78 --- /dev/null +++ b/src/DFA/DFAGraphVertex.cpp @@ -0,0 +1,58 @@ +#include "DFA/DFAGraph.hpp" +#include + +using Vertex = DFA::DFAGraph::Vertex; + +Vertex::Vertex(DFAGraph* owner) : owner_(owner) {} + +bool Vertex::IsFinal() const { + return is_final_; +} + +bool Vertex::IsStart() const { + return is_start_; +} + +size_t Vertex::GetNumber() const { + return number_; +} + +const std::map& Vertex::GetTransitions() const { + return transitions_; +} + +const std::map& Vertex::GetBackTransitions() const { + return back_transitions_; +} + +void Vertex::AddEdge(char symbol, size_t number) { + transitions_[symbol] = number; + owner_->GetVertex(number)->back_transitions_[symbol] = number_; +} + +void Vertex::RemoveEdge(char symbol) { + owner_->GetVertex(transitions_[symbol])->back_transitions_.erase(symbol); + transitions_.erase(symbol); +} + +void Vertex::SetOwner(DFAGraph* owner) { + owner_ = owner; +} + +void Vertex::SetFinal(bool status) { + if (status != is_final_) { + if (status) + owner_->AddFinalVertex(number_); + else + owner_->RemoveFinalVertex(number_); + } +} + +void Vertex::SetStart(bool status) { + if (status != is_start_) { + if (status) + owner_->AddStartVertex(number_); + else + owner_->RemoveStartVertex(number_); + } +} diff --git a/src/FDFA/FDFAGraph.cpp b/src/FDFA/FDFAGraph.cpp new file mode 100644 index 0000000..310bfec --- /dev/null +++ b/src/FDFA/FDFAGraph.cpp @@ -0,0 +1,98 @@ +#include "FDFA/FDFAGraph.hpp" +#include +#include + +namespace FDFA { +size_t FDFAGraph::AddNewVertex() { + vertexes_[count_vertexes_] = std::make_shared(this); + vertexes_[count_vertexes_]->number_ = count_vertexes_; + return count_vertexes_++; +} + +void FDFAGraph::AddFinalVertex(size_t number) { + if (!vertexes_[number]->is_final_) { + vertexes_[number]->is_final_ = true; + final_vertexes_.push_back(number); + } +} + +void FDFAGraph::AddStartVertex(size_t number) { + if (!vertexes_[number]->is_start_) { + vertexes_[number]->is_start_ = true; + start_vertexes_.push_back(number); + } +} + +void FDFAGraph::RemoveVertex(size_t number) { + RemoveFinalVertex(number); + RemoveStartVertex(number); + vertexes_.erase(number); +} + +void FDFAGraph::RemoveFinalVertex(size_t number) { + for (size_t i = 0; i < final_vertexes_.size(); ++i) { + if (final_vertexes_[i] == number) { + vertexes_[number]->is_final_ = false; + std::swap(final_vertexes_[i], final_vertexes_.back()); + final_vertexes_.pop_back(); + break; + } + } +} + +void FDFAGraph::RemoveStartVertex(size_t number) { + for (size_t i = 0; i < start_vertexes_.size(); ++i) { + if (start_vertexes_[i] == number) { + vertexes_[number]->is_start_ = false; + std::swap(start_vertexes_[i], start_vertexes_.back()); + start_vertexes_.pop_back(); + break; + } + } +} + +std::shared_ptr FDFAGraph::GetVertex(size_t number) { + if (vertexes_.count(number)) + return vertexes_[number]; + return nullptr; +} + +size_t FDFAGraph::GetCountVertexes() const { + return count_vertexes_; +} + +const std::vector& FDFAGraph::GetFinalVertexes() const { + return final_vertexes_; +} + +const std::vector& FDFAGraph::GetStartVertexes() const { + return start_vertexes_; +} + +void FDFAGraph::Print() const { + for (auto i: vertexes_) { + std::cout << i.second->number_ << " " << "f-" << i.second->is_final_ << " s-" << + i.second->is_start_ << std::endl; + } + for (auto& i: vertexes_) { + for (auto& j: i.second->transitions_) { + std::cout << i.second->number_ << "->" << j.second << " <" << j.first << ">" << + std::endl; + } + } + std::cout << std::endl; +} + +bool FDFAGraph::Accepted(const std::string& str) const { + std::shared_ptr current = vertexes_.at(start_vertexes_[0]); + for (auto i: str) { + if (current->GetTransitions().count(i)) { + current = vertexes_.at(current->GetTransitions().at(i)); + } else { + return false; + } + } + return current->IsFinal(); +} +} + diff --git a/src/FDFA/FDFAGraphVertex.cpp b/src/FDFA/FDFAGraphVertex.cpp new file mode 100644 index 0000000..8304387 --- /dev/null +++ b/src/FDFA/FDFAGraphVertex.cpp @@ -0,0 +1,58 @@ +#include "FDFA/FDFAGraph.hpp" +#include + +using Vertex = FDFA::FDFAGraph::Vertex; + +Vertex::Vertex(FDFAGraph* owner) : owner_(owner) {} + +bool Vertex::IsFinal() const { + return is_final_; +} + +bool Vertex::IsStart() const { + return is_start_; +} + +size_t Vertex::GetNumber() const { + return number_; +} + +const std::map& Vertex::GetTransitions() const { + return transitions_; +} + +const std::map& Vertex::GetBackTransitions() const { + return back_transitions_; +} + +void Vertex::AddEdge(char symbol, size_t number) { + transitions_[symbol] = number; + owner_->GetVertex(number)->back_transitions_[symbol] = number_; +} + +void Vertex::RemoveEdge(char symbol) { + owner_->GetVertex(transitions_[symbol])->back_transitions_.erase(symbol); + transitions_.erase(symbol); +} + +void Vertex::SetOwner(FDFAGraph* owner) { + owner_ = owner; +} + +void Vertex::SetFinal(bool status) { + if (status != is_final_) { + if (status) + owner_->AddFinalVertex(number_); + else + owner_->RemoveFinalVertex(number_); + } +} + +void Vertex::SetStart(bool status) { + if (status != is_start_) { + if (status) + owner_->AddStartVertex(number_); + else + owner_->RemoveStartVertex(number_); + } +} diff --git a/src/NFA/NFATree.cpp b/src/NFA/NFATree.cpp index cf2f8f8..aa57d47 100644 --- a/src/NFA/NFATree.cpp +++ b/src/NFA/NFATree.cpp @@ -3,8 +3,33 @@ #include namespace NFA { +NFATree::NFATree(NFATree&& 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; +} + +NFATree& NFATree::operator=(NFATree&& 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 NFATree::AddNewVertex() { - vertexes_[count_vertexes_] = std::make_shared(); + vertexes_[count_vertexes_] = std::make_shared(this); vertexes_[count_vertexes_]->number_ = count_vertexes_; return count_vertexes_++; } @@ -60,11 +85,24 @@ void NFATree::Composition(NFATree&& tree, size_t new_count_vertexes = count_vertexes_; for (auto& i: tree.vertexes_) { - new_count_vertexes = std::max(new_count_vertexes, i.first + count_vertexes_); + new_count_vertexes = std::max(new_count_vertexes, i.first + count_vertexes_ + 1); i.second->number_ += count_vertexes_; - for (auto& j: i.second->transitions) { - j.second += count_vertexes_; + std::map> new_transitions; + for (auto& j: i.second->transitions_) { + for (auto& k: j.second) { + new_transitions[j.first].insert(k + count_vertexes_); + } } + std::map> new_back_transitions; + for (auto& j: i.second->back_transitions_) { + for (auto& k: j.second) { + new_back_transitions[j.first].insert(k + count_vertexes_); + } + } + i.second->transitions_ = std::move(new_transitions); + i.second->back_transitions_ = std::move(new_back_transitions); + + i.second->SetOwner(this); vertexes_[i.second->number_] = std::move(i.second); } @@ -79,12 +117,14 @@ void NFATree::Composition(NFATree&& tree, for (auto& i: start_vertexes) { for (auto& j: add_start_vertexes) { - vertexes_[i]->transitions.emplace(' ', j); + vertexes_[i]->transitions_[' '].insert(j); + vertexes_[j]->back_transitions_[' '].insert(i); } } for (auto& i: add_final_vertexes) { for (auto& j: final_vertexes) { - vertexes_[i]->transitions.emplace(' ', j); + vertexes_[i]->transitions_[' '].insert(j); + vertexes_[j]->back_transitions_[' '].insert(i); } } for (auto& i: add_final_vertexes) { @@ -119,12 +159,13 @@ void NFATree::Print() const { i.second->is_start_ << std::endl; } for (auto& i: vertexes_) { - for (auto& j: i.second->transitions) { - std::cout << i.second->number_ << "->" << j.second << " <" << j.first << ">" << + for (auto& j: i.second->transitions_) { + for (auto k: j.second) { + std::cout << i.second->number_ << "->" << k << " <" << j.first << ">" << std::endl; + } } } std::cout << std::endl; } } - diff --git a/src/NFA/NFATreeVertex.cpp b/src/NFA/NFATreeVertex.cpp index cc9ca82..4060d82 100644 --- a/src/NFA/NFATreeVertex.cpp +++ b/src/NFA/NFATreeVertex.cpp @@ -1,11 +1,9 @@ #include "NFA/NFATree.hpp" +#include using Vertex = NFA::NFATree::Vertex; -Vertex::Vertex() {} - -Vertex::Vertex(bool is_final, bool is_start) : is_final_(is_final), - is_start_(is_start) {} +Vertex::Vertex(NFATree* owner) : owner_(owner) {} bool Vertex::IsFinal() const { return is_final_; @@ -19,3 +17,47 @@ size_t Vertex::GetNumber() const { return number_; } +const std::map>& Vertex::GetTransitions() const { + return transitions_; +} + +const std::map>& Vertex::GetBackTransitions() const { + return back_transitions_; +} + +void Vertex::AddEdge(char symbol, size_t number) { + transitions_[symbol].insert(number); + owner_->GetVertex(number)->back_transitions_[symbol]; + owner_->GetVertex(number)->back_transitions_[symbol].insert(number_); +} + +void Vertex::RemoveEdge(char symbol, size_t number) { + transitions_[symbol].erase(number); + if (transitions_[symbol].size() == 0) + transitions_.erase(symbol); + owner_->GetVertex(number)->back_transitions_[symbol].erase(number_); + if (owner_->GetVertex(number)->back_transitions_[symbol].size() == 0) + owner_->GetVertex(number)->back_transitions_.erase(symbol); +} + +void Vertex::SetOwner(NFATree* owner) { + owner_ = owner; +} + +void Vertex::SetFinal(bool status) { + if (status != is_final_) { + if (status) + owner_->AddFinalVertex(number_); + else + owner_->RemoveFinalVertex(number_); + } +} + +void Vertex::SetStart(bool status) { + if (status != is_start_) { + if (status) + owner_->AddStartVertex(number_); + else + owner_->RemoveStartVertex(number_); + } +} diff --git a/src/converters/DFAToFDFA.cpp b/src/converters/DFAToFDFA.cpp new file mode 100644 index 0000000..9d6ec37 --- /dev/null +++ b/src/converters/DFAToFDFA.cpp @@ -0,0 +1,90 @@ +#include "converters/DFAToFDFA.hpp" + +namespace converters { +DFAGraph DFAGraphToFDFAGraph(DFAGraph&& graph, const std::vector& alphabet) { + DFAGraph result; + const int n = graph.GetCountVertexes(); + std::map number_vertex_in_DFA; + for (int i = 0; i < n; ++i) { + if (!graph.GetVertex(i)) continue; + number_vertex_in_DFA[i] = result.AddNewVertex(); + } + for (int i = 0; i < n; ++i) { + if (!graph.GetVertex(i)) continue; + if (graph.GetVertex(i)->IsFinal()) + result.GetVertex(number_vertex_in_DFA[i])->SetFinal(true); + if (graph.GetVertex(i)->IsStart()) + result.GetVertex(number_vertex_in_DFA[i])->SetStart(true); + + const auto& transitions = graph.GetVertex(i)->GetTransitions(); + for (const auto& t: transitions) { + result.GetVertex(number_vertex_in_DFA[i])->AddEdge(t.first, t.second); + } + } + + size_t drain = result.AddNewVertex(); + + for (int i = 0; i < n; ++i) { + const auto& transitions = graph.GetVertex(i)->GetTransitions(); + for (char j: alphabet) { + if (!transitions.count(j)) { + result.GetVertex(i)->AddEdge(j, drain); + } + } + } + + if (result.GetVertex(drain)->GetBackTransitions().size() == 0) { + result.RemoveVertex(drain); + } else { + for (char j: alphabet) { + result.GetVertex(drain)->AddEdge(j, drain); + } + } + + return result; +} +/* +FDFAGraph DFAGraphToFDFAGraph(DFAGraph&& graph, const std::vector& alphabet) { + FDFAGraph result; + const int n = graph.GetCountVertexes(); + std::map number_vertex_in_DFA; + for (int i = 0; i < n; ++i) { + if (!graph.GetVertex(i)) continue; + number_vertex_in_DFA[i] = result.AddNewVertex(); + } + for (int i = 0; i < n; ++i) { + if (!graph.GetVertex(i)) continue; + if (graph.GetVertex(i)->IsFinal()) + result.GetVertex(number_vertex_in_DFA[i])->SetFinal(true); + if (graph.GetVertex(i)->IsStart()) + result.GetVertex(number_vertex_in_DFA[i])->SetStart(true); + + const auto& transitions = graph.GetVertex(i)->GetTransitions(); + for (const auto& t: transitions) { + result.GetVertex(number_vertex_in_DFA[i])->AddEdge(t.first, t.second); + } + } + + size_t drain = result.AddNewVertex(); + + for (int i = 0; i < n; ++i) { + const auto& transitions = graph.GetVertex(i)->GetTransitions(); + for (char j: alphabet) { + if (!transitions.count(j)) { + result.GetVertex(i)->AddEdge(j, drain); + } + } + } + + if (result.GetVertex(drain)->GetBackTransitions().size() == 0) { + result.RemoveVertex(drain); + } else { + for (char j: alphabet) { + result.GetVertex(drain)->AddEdge(j, drain); + } + } + + return result; +} +*/ +} diff --git a/src/converters/DFAToMinDFA.cpp b/src/converters/DFAToMinDFA.cpp new file mode 100644 index 0000000..2cc349c --- /dev/null +++ b/src/converters/DFAToMinDFA.cpp @@ -0,0 +1,111 @@ +#include "converters/DFAToMinDFA.hpp" +#include +#include + +namespace converters { +DFAGraph DFAToMinDFA(DFAGraph&& graph) { + const int n = graph.GetCountVertexes(); + DFAGraph result; + + std::vector alphabet; + + { + std::set salphabet; + for (int i = 0; i < n; ++i) { + for (auto i: graph.GetVertex(i)->GetTransitions()) { + salphabet.insert(i.first); + } + } + alphabet = std::vector(salphabet.begin(), salphabet.end()); + } + + std::vector>> table(n, + std::vector>(n, std::vector(alphabet.size() + 1))); + + { + std::vector>& layer(table[0]); + for (int i = 0; i < n; ++i) { + layer[i][0] = graph.GetVertex(i)->IsFinal(); + } + for (int i = 0; i < n; ++i) { + for (int j = 0; j < alphabet.size(); ++j) { + const auto& transitions = graph.GetVertex(i)->GetTransitions(); + if (transitions.count(alphabet[j])) + layer[i][j + 1] = layer[transitions.at(alphabet[j])][0]; + else + layer[i][j + 1] = -1; + } + } + } + + for (int number_layer = 1; number_layer < n; ++number_layer) { + size_t count_types = 0; + std::vector>& prev_layer(table[number_layer - 1]); + std::vector>& layer(table[number_layer]); + for (int i = 0; i < n; ++i) { + bool is_find = false; + for (int j = 0; j < i; ++j) { + if (prev_layer[j] == prev_layer[i]) { + layer[i][0] = layer[j][0]; + is_find = true; + break; + } + } + if (!is_find) { + layer[i][0] = count_types++; + } + } + for (int i = 0; i < n; ++i) { + for (int j = 0; j < alphabet.size(); ++j) { + const auto& transitions = graph.GetVertex(i)->GetTransitions(); + if (transitions.count(alphabet[j])) + layer[i][j + 1] = layer[transitions.at(alphabet[j])][0]; + else + layer[i][j + 1] = -1LL; + } + } + } + + /* + for (int i = 0; i < n; ++i) { + for (int k = 0; k < n; ++k) { + for (int j = 0; j < alphabet.size() + 1; ++j) { + std::cout << table[k][i][j] << " "; + } + std::cout << "| "; + } + std::cout << std::endl; + } + */ + + std::vector>& last_layer(table.back()); + size_t count_vertex = 0; + + for (int i = 0; i < n; ++i) { + count_vertex = std::max(count_vertex, last_layer[i][0]); + } + count_vertex++; + + std::map number_vertex_in_DFA; + for (int i = 0; i < count_vertex; ++i) { + number_vertex_in_DFA[i] = result.AddNewVertex(); + } + + for (int i = 0; i < n; ++i) { + size_t v = number_vertex_in_DFA[last_layer[i][0]]; + + const auto& transitions = graph.GetVertex(i)->GetTransitions(); + for (const auto& t: transitions) { + if (last_layer[t.second][0] != -1LL) { + size_t u = number_vertex_in_DFA[last_layer[t.second][0]]; + result.GetVertex(v)->AddEdge(t.first, u); + } + } + + if (graph.GetVertex(i)->IsStart()) result.GetVertex(v)->SetStart(true); + if (graph.GetVertex(i)->IsFinal()) result.GetVertex(v)->SetFinal(true); + } + + return result; +} +} diff --git a/src/converters/DFAToRegular.cpp b/src/converters/DFAToRegular.cpp new file mode 100644 index 0000000..c19834c --- /dev/null +++ b/src/converters/DFAToRegular.cpp @@ -0,0 +1,126 @@ +#include "converters/DFAToRegular.hpp" +#include +#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.GetVertex(i)) continue; + if (graph.GetVertex(i)->IsStart()) start = i; + } + + rename[start] = 1; + int cnt = 2; + + for (int i = 0; i < n - 1; ++i) { + if (i == start) continue; + rename[i] = cnt++; + } + + + for (int i = 0; i < n - 1; ++i) { + if (!graph.GetVertex(i)) continue; + const auto& vertex_transitions = graph.GetVertex(i)->GetTransitions(); + + for (auto j: vertex_transitions) { + transitions[rename[i]][rename[j.second]].insert(std::string(1, j.first)); + } + if (graph.GetVertex(i)->IsFinal()) { + transitions[rename[i]][0].insert("( )"); + } + } + + for (int i = n - 1; i > 1; --i) { + std::vector>> new_transitions(n, + std::vector>(n)); + std::string loop = ""; + if (transitions[i][i].size() != 0) { + for (const std::string s: transitions[i][i]) { + loop += "("; + loop += s; + loop += ")"; + loop += "|"; + } + if (loop.size()) + loop.pop_back(); + if (transitions[i][i].size() > 1) + loop = "(" + loop + ")*"; + else + loop += "*"; + } + + for (int j = 0; j < i; ++j) { + if (transitions[j][i].size() == 0) continue; + std::string j_to_i = ""; + for (const std::string s: transitions[j][i]) { + j_to_i += "("; + j_to_i += s; + j_to_i += ")"; + j_to_i += "|"; + } + if (j_to_i.size()) + j_to_i.pop_back(); + if (transitions[j][i].size() > 1) + j_to_i = "(" + j_to_i + ")"; + + for (int k = 0; k < i; ++k) { + if (transitions[i][k].size() == 0) continue; + std::string i_to_k = ""; + for (const std::string s: transitions[i][k]) { + i_to_k += "("; + i_to_k += s; + i_to_k += ")"; + i_to_k += "|"; + } + if (i_to_k.size()) + i_to_k.pop_back(); + if (transitions[i][k].size() > 1) + i_to_k = "(" + j_to_i + ")"; + + new_transitions[j][k].insert(j_to_i + loop + i_to_k); + } + } + + for (int j = 0; j < i; ++j) { + for (int k = 0; k < i; ++k) { + transitions[j][k].insert(new_transitions[j][k].begin(), new_transitions[j][k].end()); + } + } + } + + std::string loop; + std::string begin_to_end; + + if (transitions[1][1].size() != 0) { + for (const std::string s: transitions[1][1]) { + loop += "("; + loop += s; + loop += ")"; + loop += "|"; + } + if (loop.size()) + loop.pop_back(); + loop = "(" + loop + ")*"; + } + for (const std::string s: transitions[1][0]) { + begin_to_end += "("; + begin_to_end += s; + begin_to_end += ")"; + begin_to_end += "|"; + } + if (begin_to_end.size()) + begin_to_end.pop_back(); + + std::string res(loop + "(" + begin_to_end + ")"); + return res; +} +} diff --git a/src/converters/NFAToDFA.cpp b/src/converters/NFAToDFA.cpp new file mode 100644 index 0000000..c2ac47c --- /dev/null +++ b/src/converters/NFAToDFA.cpp @@ -0,0 +1,293 @@ +#include "converters/NFAToDFA.hpp" +#include +#include +#include + +namespace converters { +/* +OLD version + + +NFATree AddAllEpsilonTransitions(NFATree&& tree) { + // Algorithm from 2-sat + const int n = tree.GetCountVertexes(); + std::vector used(n, false); + std::vector component(n, -1); + std::vector order; + + std::function dfs_order = [&tree, &used, &order, &dfs_order](int v) -> void { + used[v] = true; + const auto& transitions = tree.GetVertex(v)->GetTransitions(); + if (transitions.count(' ')) { + const auto& s = transitions.at(' '); + for (auto i: s) { + if (!used[i]) { + dfs_order(i); + } + } + } + order.push_back(v); + }; + + std::function dfs_component = [&tree, &component, + &dfs_component](int v, int c) -> void { + component[v] = c; + const auto& transitions = tree.GetVertex(v)->GetBackTransitions(); + if (transitions.count(' ')) { + const auto& s = transitions.at(' '); + for (auto i: s) { + if (component[i] == -1) { + dfs_component(i, c); + } + } + } + }; + + for (int i = 0; i < n; ++i) { + if (!used[i] && tree.GetVertex(i)) { + dfs_order(i); + } + } + + int current_component = 0; + for (int i = 0; i < n; ++i) { + int v = order[n - i - 1]; + if (component[v] == -1 && tree.GetVertex(i)) { + dfs_component(v, current_component++); + } + } + + std::set> connectivity_components; + + used.assign(n, false); + std::vector> connectivity_from(current_component); + + std::function dfs_connectivity = [&tree, &component, + &used, &dfs_connectivity, &connectivity_from](int v) -> void { + used[v] = true; + const auto& transitions = tree.GetVertex(v)->GetTransitions(); + if (transitions.count(' ')) { + const auto& s = transitions.at(' '); + for (auto i: s) { + if (!used[i]) { + dfs_connectivity(i); + } + if (component[v] != component[i]) { + connectivity_from[component[v]].insert(connectivity_from[component[i]].begin(), + connectivity_from[component[i]].end()); + connectivity_from[component[v]].insert(component[i]); + } + } + } + }; + + for (int i = 0; i < n; ++i) { + if (!tree.GetVertex(i)) continue; + connectivity_components.emplace(component[i], component[i]); + if (!used[i]) { + dfs_connectivity(i); + } + for (int j: connectivity_from[component[i]]) { + std::cout << i << " " << j << std::endl; + connectivity_components.emplace(component[i], j); + } + } + + for (int i = 0; i < n; ++i) { + std::cout << component[i] << " "; + } + std::cout << std::endl; + for (int i: connectivity_from[1]) { + std::cout << i << " "; + } + std::cout << std::endl; + + + + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + if (i == j) continue; + if (connectivity_components.count(std::make_pair(component[i], component[j]))) { + tree.GetVertex(i)->AddEdge(' ', j); + } + } + } + + return std::move(tree); +} +*/ + +NFATree AddAllEpsilonTransitions(NFATree&& tree) { + const int n = tree.GetCountVertexes(); + std::vector used(n, false); + + std::function dfs = [&tree, &used, &dfs](int u, int v) -> void { + used[v] = true; + const auto& transitions = tree.GetVertex(v)->GetTransitions(); + if (transitions.count(' ')) { + const auto& s = transitions.at(' '); + for (auto i: s) { + if (!used[i]) { + if (u != i) + tree.GetVertex(u)->AddEdge(' ', i); + dfs(u, i); + } + } + } + }; + + for (int i = 0; i < n; ++i) { + if (!tree.GetVertex(i)) continue; + + used.assign(n, false); + dfs(i, i); + } + return std::move(tree); +} + +NFATree AddAllPossibleStartFilnal(NFATree&& tree) { + if (tree.GetStartVertexes().size() != 1) { + size_t start_vertex = tree.AddNewVertex(); + for (auto v: tree.GetStartVertexes()) { + tree.GetVertex(start_vertex)->AddEdge(' ', v); + } + } + for (const auto& v: tree.GetFinalVertexes()) { + const auto& transitions = tree.GetVertex(v)->GetBackTransitions(); + if (transitions.count(' ')) { + const auto& s = transitions.at(' '); + for (auto i: s) { + tree.GetVertex(i)->SetFinal(true); + } + } + } + return std::move(tree); +} + +NFATree DeleteEpsilonTransitions(NFATree&& tree) { + const int n = tree.GetCountVertexes(); + + for (int v = 0; v < n; ++v) { + if (!tree.GetVertex(v)) continue; + + const auto& transitions = tree.GetVertex(v)->GetTransitions(); + if (transitions.count(' ')) { + auto s = transitions.at(' '); + for (auto u: s) { + for (auto& i: tree.GetVertex(u)->GetTransitions()) { + if (i.first == ' ') continue; + for (auto t: i.second) { + tree.GetVertex(v)->AddEdge(i.first, t); + } + } + } + for (auto u: s) { + tree.GetVertex(v)->RemoveEdge(' ', u); + } + } + } + return std::move(tree); +} + +NFATree DeleteTransitionsByOneLetter(NFATree&& tree) { + const int n = tree.GetCountVertexes(); + + NFATree result_tree; + + std::map, char>, std::set> transitions; + std::map, size_t> number_vertex_in_result_tree; + std::queue> queue; + + std::set alphabet; + for (int i = 0; i < n; ++i) { + if (!tree.GetVertex(i)) continue; + for (const auto& j: tree.GetVertex(i)->GetTransitions()) { + if (j.second.size() > 0) + alphabet.insert(j.first); + } + } + + for (auto i: tree.GetStartVertexes()) { + queue.push({i}); + number_vertex_in_result_tree[{i}] = result_tree.AddNewVertex(); + } + + while (!queue.empty()) { + auto current = queue.front(); + queue.pop(); + + for (auto symbol: alphabet) { + std::set result; + for (auto v: current) { + const auto& transitions = tree.GetVertex(v)->GetTransitions(); + if (transitions.count(symbol)) { + const auto& s = transitions.at(symbol); + result.insert(s.begin(), s.end()); + } + } + + if (result.size() == 0) continue; + + transitions[std::make_pair(current, symbol)] = result; + if (!number_vertex_in_result_tree.count(result)) { + queue.push(result); + number_vertex_in_result_tree[result] = result_tree.AddNewVertex(); + } + } + } + + for (auto i: transitions) { + int v = number_vertex_in_result_tree[i.first.first]; + int u = number_vertex_in_result_tree[i.second]; + char symbol = i.first.second; + result_tree.GetVertex(v)->AddEdge(symbol, u); + } + + for (auto i: number_vertex_in_result_tree) { + auto s = i.first; + auto v = i.second; + + for (auto i: s) { + if (tree.GetVertex(i)->IsFinal()) + result_tree.GetVertex(v)->SetFinal(true); + if (tree.GetVertex(i)->IsStart()) + result_tree.GetVertex(v)->SetStart(true); + } + } + + return result_tree; +} + +DFAGraph NFATreeToDFAGraph(NFATree&& tree) { + /* + tree = AddAllEpsilonTransitions(std::move(tree)); + tree = AddAllPossibleStartFilnal(std::move(tree)); + tree = DeleteEpsilonTransitions(std::move(tree)); + tree = DeleteTransitionsByOneLetter(std::move(tree)); + */ + tree = DeleteTransitionsByOneLetter(DeleteEpsilonTransitions(AddAllPossibleStartFilnal( + AddAllEpsilonTransitions(std::move(tree))))); + + const int n = tree.GetCountVertexes(); + DFAGraph result; + std::map number_vertex_in_DFA; + for (int i = 0; i < n; ++i) { + if (!tree.GetVertex(i)) continue; + number_vertex_in_DFA[i] = result.AddNewVertex(); + } + for (int i = 0; i < n; ++i) { + if (!tree.GetVertex(i)) continue; + if (tree.GetVertex(i)->IsFinal()) + result.GetVertex(number_vertex_in_DFA[i])->SetFinal(true); + if (tree.GetVertex(i)->IsStart()) + result.GetVertex(number_vertex_in_DFA[i])->SetStart(true); + + const auto& transitions = tree.GetVertex(i)->GetTransitions(); + for (const auto& t: transitions) { + if (t.second.size() != 1) throw std::logic_error(""); + result.GetVertex(number_vertex_in_DFA[i])->AddEdge(t.first, *t.second.begin()); + } + } + return result; +} +} diff --git a/src/converters/RegularToNFA.cpp b/src/converters/RegularToNFA.cpp index 12e3c7c..54c59b2 100644 --- a/src/converters/RegularToNFA.cpp +++ b/src/converters/RegularToNFA.cpp @@ -1,6 +1,7 @@ #include "converters/RegularToNFA.hpp" #include "regular/RegularTree.hpp" #include "NFA/NFATree.hpp" +#include using namespace NFA; using namespace regular; @@ -15,14 +16,21 @@ template NFATree RegularToNFA(std::unique_ptr node) { NFATree result; if (node->type == Node::Type::Word) { - auto last = result.AddNewVertex(); - result.AddStartVertex(last); + auto end = result.AddNewVertex(); + auto start = end; + result.AddStartVertex(end); for (char i: node->word) { auto tmp = result.AddNewVertex(); - result.GetVertex(last)->transitions.emplace(i, tmp); - last = tmp; + result.GetVertex(end)->AddEdge(i, tmp); + end = tmp; } - result.AddFinalVertex(last); + if (node->modifier == Node::Modifier::Plus) { + result.GetVertex(end)->AddEdge(' ', start); + } else if (node->modifier == Node::Modifier::Star) { + result.GetVertex(end)->AddEdge(' ', start); + result.GetVertex(start)->AddEdge(' ', end); + } + result.AddFinalVertex(end); } else if (node->type == Node::Type::Concatenation) { result = RegularToNFA(std::move(node->children[0])); for (auto it = node->children.begin() + 1; it != node->children.end(); ++it) { @@ -34,9 +42,39 @@ NFATree RegularToNFA(std::unique_ptr node) { } result.AddFinalVertex(v); } + const auto& start_vertexes = result.GetStartVertexes(); + const auto& end_vertexes = result.GetFinalVertexes(); + + if (node->modifier == Node::Modifier::Plus) { + for (auto start: start_vertexes) { + for (auto end: end_vertexes) { + result.GetVertex(end)->AddEdge(' ', start); + } + } + } else if (node->modifier == Node::Modifier::Star) { + for (auto start: start_vertexes) { + for (auto end: end_vertexes) { + result.GetVertex(end)->AddEdge(' ', start); + result.GetVertex(start)->AddEdge(' ', end); + } + } + } } else if (node->type == Node::Type::Addition) { - // TODO + auto start = result.AddNewVertex(); + result.AddStartVertex(start); + auto end = result.AddNewVertex(); + result.AddFinalVertex(end); + for (auto& i: node->children) { + auto tmp = RegularToNFA(std::move(i)); + result.Composition(std::move(tmp), {start}, {end}); + } + if (node->modifier == Node::Modifier::Plus) { + result.GetVertex(end)->AddEdge(' ', start); + } else if (node->modifier == Node::Modifier::Star) { + result.GetVertex(end)->AddEdge(' ', start); + result.GetVertex(start)->AddEdge(' ', end); + } } return result; } diff --git a/src/main.cpp b/src/main.cpp index 3253512..0f1f819 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,163 @@ #include +#include #include "regular/RegularTree.hpp" #include "converters/RegularToNFA.hpp" +#include "converters/NFAToDFA.hpp" +#include "converters/DFAToFDFA.hpp" +#include "converters/DFAToMinDFA.hpp" +#include "converters/DFAToRegular.hpp" + +using namespace regular; +using namespace regular; +using namespace NFA; +using namespace DFA; +using namespace converters; int main() { - using namespace regular; + { + RegularTree r("a*"); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + DFA_graph.Print(); + + std::string reg = DFAGraphToRegular(std::move(DFA_graph)); + + r = RegularTree(reg); + NFA_tree = RegularToNFA(std::move(r)); + DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + DFA_graph.Print(); + } + + return 0; + + + { + RegularTree r("a+"); + r.Print(); + NFA::NFATree NFA_tree = converters::RegularToNFA(std::move(r)); + NFA_tree.Print(); + DFA::DFAGraph DFA_graph = converters::NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph.Print(); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + DFA_graph.Print(); + } + + return 0; + NFA::NFATree 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::NFATreeToDFAGraph(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::DFAToMinDFA(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); diff --git a/src/regular/RegularTreeNode.cpp b/src/regular/RegularTreeNode.cpp index 3939d17..f103293 100644 --- a/src/regular/RegularTreeNode.cpp +++ b/src/regular/RegularTreeNode.cpp @@ -16,7 +16,6 @@ void Node::Print() const { } void Node::ParseCurrentType(const std::string_view regular) { - std::cout << "# " << regular << std::endl; const size_t n = regular.size(); children.clear(); word.clear(); @@ -82,8 +81,8 @@ void Node::ParseCurrentType(const std::string_view regular) { if (balance == 1) { if (begin_child < i) { AddChild(regular.substr(begin_child, i - begin_child)); - begin_child = i + 1; } + begin_child = i + 1; } } else if (regular[i] == ')') { --balance; @@ -95,12 +94,27 @@ void Node::ParseCurrentType(const std::string_view regular) { if (balance != 0) { throw std::logic_error("invalid regular"); } + if (children.size() == 0) { type = Type::Word; break; } else { - AddChild(regular.substr(begin_child, i - begin_child + 1)); - begin_child = i + 1; + if (regular[i] == '+') { + if (begin_child < i) { + AddChild(regular.substr(begin_child, i - begin_child)); + } + children.back()->modifier = Modifier::Plus; + begin_child = i + 1; + } else if (regular[i] == '*') { + if (begin_child < i) { + AddChild(regular.substr(begin_child, i - begin_child)); + } + children.back()->modifier = Modifier::Star; + begin_child = i + 1; + } else { + AddChild(regular.substr(begin_child, i - begin_child + 1)); + begin_child = i + 1; + } } } else if (balance == 0) { if (regular[i] == '+') { diff --git a/tests/DFAToRegular/DFAToRegular.cpp b/tests/DFAToRegular/DFAToRegular.cpp new file mode 100644 index 0000000..01c465e --- /dev/null +++ b/tests/DFAToRegular/DFAToRegular.cpp @@ -0,0 +1,202 @@ +#include +#include +#include "regular/RegularTree.hpp" +#include "converters/RegularToNFA.hpp" +#include "converters/NFAToDFA.hpp" +#include "converters/DFAToMinDFA.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(DFA_to_regular, a_star) { + RegularTree r("a*"); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + std::string reg = DFAGraphToRegular(std::move(DFA_graph)); + + r = RegularTree(reg); + NFA_tree = RegularToNFA(std::move(r)); + DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + + std::string s = ""; + for (int i = 0; i < 100; ++i) { + ASSERT_EQ(DFA_graph.Accepted(s), true); + s += "a"; + } +} + +TEST(DFA_to_regular, a_plus) { + std::string regulars[] = {"a+", "(a)+", "(a+)"}; + for (const auto& regular: regulars) { + RegularTree r(regular); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + std::string reg = DFAGraphToRegular(std::move(DFA_graph)); + + r = RegularTree(reg); + NFA_tree = RegularToNFA(std::move(r)); + DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + std::string s = ""; + ASSERT_EQ(DFA_graph.Accepted(s), false); + s += "a"; + for (int i = 0; i < 100; ++i) { + ASSERT_EQ(DFA_graph.Accepted(s), true); + s += "a"; + } + } +} + +TEST(DFA_to_regular, abc) { + std::string regulars[] = {"abc"}; + for (const auto& regular: regulars) { + RegularTree r(regular); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + std::string reg = DFAGraphToRegular(std::move(DFA_graph)); + + r = RegularTree(reg); + NFA_tree = RegularToNFA(std::move(r)); + DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + ASSERT_EQ(DFA_graph.Accepted("abc"), true); + 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), false); + } + } +} + +TEST(DFA_to_regular, a_or_b_or_c) { + std::string regulars[] = {}; + for (const auto& regular: regulars) { + RegularTree r("a|b|c"); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + std::string reg = DFAGraphToRegular(std::move(DFA_graph)); + + r = RegularTree(reg); + NFA_tree = RegularToNFA(std::move(r)); + DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + ASSERT_EQ(DFA_graph.Accepted("a"), true); + ASSERT_EQ(DFA_graph.Accepted("b"), true); + ASSERT_EQ(DFA_graph.Accepted("c"), true); + 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), false); + } + } +} + +TEST(DFA_to_regular, 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); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + std::string reg = DFAGraphToRegular(std::move(DFA_graph)); + + r = RegularTree(reg); + NFA_tree = RegularToNFA(std::move(r)); + DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(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(""), true); + 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(DFA_to_regular, _a_star_or_b_star_or_c_star_plus) { + RegularTree r("(a*|b*|c*)+"); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + std::string reg = DFAGraphToRegular(std::move(DFA_graph)); + + r = RegularTree(reg); + NFA_tree = RegularToNFA(std::move(r)); + DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(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(""), true); + 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(DFA_to_regular, _a_or_b_or_c_star_plus) { + RegularTree r("(a|b|c*)+"); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + std::string reg = DFAGraphToRegular(std::move(DFA_graph)); + + r = RegularTree(reg); + NFA_tree = RegularToNFA(std::move(r)); + DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(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(""), true); + 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/NFAToDFA/check_equivalence.cpp b/tests/NFAToDFA/check_equivalence.cpp new file mode 100644 index 0000000..579632c --- /dev/null +++ b/tests/NFAToDFA/check_equivalence.cpp @@ -0,0 +1,111 @@ +#include +#include +#include "DFA/DFAGraph.hpp" +#include "NFA/NFATree.hpp" +#include "converters/NFAToDFA.hpp" + +using namespace NFA; +using namespace DFA; +using namespace converters; + +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 res; +} + +TEST(check_equivalence_NFA_to_DFA, 1) { + NFA::NFATree tree; + + const int N = 10; + int a[N]; + for (int i = 0; i < N; ++i) + a[i] = tree.AddNewVertex(); + + tree.GetVertex(a[0])->AddEdge('a', a[1]); + tree.GetVertex(a[1])->AddEdge('a', a[2]); + tree.GetVertex(a[0])->AddEdge('a', a[3]); + + tree.GetVertex(a[0])->SetStart(true); + tree.GetVertex(a[2])->SetFinal(true); + tree.GetVertex(a[3])->SetFinal(true); + + DFA::DFAGraph res = converters::NFATreeToDFAGraph(std::move(tree)); + + EXPECT_FALSE(res.Accepted("")); + EXPECT_TRUE(res.Accepted("a")); + EXPECT_TRUE(res.Accepted("aa")); + EXPECT_FALSE(res.Accepted("aaa")); + EXPECT_FALSE(res.Accepted("aaaa")); + EXPECT_FALSE(res.Accepted("aaaaa")); + EXPECT_FALSE(res.Accepted("b")); +} + +TEST(check_equivalence_NFA_to_DFA, 2) { + NFA::NFATree tree; + + const int N = 10; + int a[N]; + for (int i = 0; i < N; ++i) + a[i] = tree.AddNewVertex(); + + 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); + + DFA::DFAGraph res = converters::NFATreeToDFAGraph(std::move(tree)); + + auto check = [](const std::string& str) { + if (str.size() > 0) { + if (str[0] == 'a') { + if (str.size() == 1) { + return true; + } + if (str[1] == 'b') { + for (int i = 1; i < str.size(); ++i) { + if (str[i] != 'b') { + return false; + } + } + return true; + } + if (str[1] == 'c') { + for (int i = 1; i < str.size(); ++i) { + if (str[i] != 'c') { + return false; + } + } + return true; + } + } + } + + return false; + }; + + EXPECT_FALSE(res.Accepted("")); + EXPECT_TRUE(res.Accepted("a")); + EXPECT_FALSE(res.Accepted("aa")); + EXPECT_FALSE(res.Accepted("aaa")); + EXPECT_FALSE(res.Accepted("aaaa")); + EXPECT_FALSE(res.Accepted("aaaaa")); + EXPECT_FALSE(res.Accepted("b")); + EXPECT_TRUE(res.Accepted("ab")); + EXPECT_TRUE(res.Accepted("abb")); + EXPECT_TRUE(res.Accepted("ac")); + EXPECT_TRUE(res.Accepted("acc")); + + for (int i = 0; i < 5000; ++i) { + auto str = GenerateRandomString({'a', 'b', 'c', 'd'}, 20); + ASSERT_EQ(res.Accepted(str), check(str)); + } +} diff --git a/tests/regularToDFA/regularToDFA.cpp b/tests/regularToDFA/regularToDFA.cpp new file mode 100644 index 0000000..3d157a1 --- /dev/null +++ b/tests/regularToDFA/regularToDFA.cpp @@ -0,0 +1,151 @@ +#include +#include +#include "regular/RegularTree.hpp" +#include "converters/RegularToNFA.hpp" +#include "converters/NFAToDFA.hpp" +#include "converters/DFAToMinDFA.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(regular_to_DFA, a_star) { + RegularTree r("a*"); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + std::string s = ""; + for (int i = 0; i < 100; ++i) { + ASSERT_EQ(DFA_graph.Accepted(s), true); + s += "a"; + } +} + +TEST(regular_to_DFA, a_plus) { + std::string regulars[] = {"a+", "(a)+", "(a+)"}; + for (const auto& regular: regulars) { + RegularTree r(regular); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + std::string s = ""; + ASSERT_EQ(DFA_graph.Accepted(s), false); + s += "a"; + for (int i = 0; i < 100; ++i) { + ASSERT_EQ(DFA_graph.Accepted(s), true); + s += "a"; + } + } +} + +TEST(regular_to_DFA, abc) { + std::string regulars[] = {"abc"}; + for (const auto& regular: regulars) { + RegularTree r(regular); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + ASSERT_EQ(DFA_graph.Accepted("abc"), true); + 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), false); + } + } +} + +TEST(regular_to_DFA, a_or_b_or_c) { + std::string regulars[] = {}; + for (const auto& regular: regulars) { + RegularTree r("a|b|c"); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(std::move(DFA_graph)); + + ASSERT_EQ(DFA_graph.Accepted("a"), true); + ASSERT_EQ(DFA_graph.Accepted("b"), true); + ASSERT_EQ(DFA_graph.Accepted("c"), true); + 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), false); + } + } +} + +TEST(regular_to_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); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(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(""), true); + 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(regular_to_DFA, _a_star_or_b_star_or_c_star_plus) { + RegularTree r("(a*|b*|c*)+"); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(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(""), true); + 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(regular_to_DFA, _a_or_b_or_c_star_plus) { + RegularTree r("(a|b|c*)+"); + NFATree NFA_tree = RegularToNFA(std::move(r)); + DFAGraph DFA_graph = NFATreeToDFAGraph(std::move(NFA_tree)); + DFA_graph = DFAToMinDFA(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(""), true); + for (int i = 0; i < 1000; ++i) { + auto s = GenerateRandomString({'a', 'b', 'c', 'd'}, rnd() % 10); + + ASSERT_EQ(DFA_graph.Accepted(s), check(s)); + } +}