Add converter regular to NFA

This commit is contained in:
MaxanRus 2021-10-03 16:42:51 +03:00
parent 82822d316f
commit 45527d2c06
7 changed files with 187 additions and 42 deletions

View file

@ -20,6 +20,7 @@ set(SOURCE_FILES
src/regular/RegularTreeNode.cpp src/regular/RegularTreeNode.cpp
src/NFA/NFATree.cpp src/NFA/NFATree.cpp
src/NFA/NFATreeVertex.cpp src/NFA/NFATreeVertex.cpp
src/converters/RegularToNFA.cpp
) )
set(TEST_FILES set(TEST_FILES

View file

@ -2,6 +2,7 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include <set>
#include <memory> #include <memory>
namespace NFA { namespace NFA {
@ -10,29 +11,51 @@ class NFATree {
class Vertex { class Vertex {
public: public:
Vertex(); Vertex();
Vertex(bool is_finale, bool is_start);
bool IsFinal() const; bool IsFinal() const;
bool IsStart() const; bool IsStart() const;
void SetFinal(bool value); size_t GetNumber() const;
void SetStart(bool value);
std::map<char, std::vector<std::weak_ptr<Vertex>>> transitions; std::multimap<char, size_t> transitions;
private: private:
Vertex(bool is_final, bool is_start);
size_t number_;
bool is_final_ = false; bool is_final_ = false;
bool is_start_ = false; bool is_start_ = false;
friend class NFATree;
}; };
void RemoveVertex(std::shared_ptr<Vertex>); NFATree() = default;
void RemoveFinalVertex(std::shared_ptr<Vertex>); NFATree(const NFATree&) = delete;
void RemoveStartVertex(std::shared_ptr<Vertex>); NFATree(NFATree&&) = default;
void Composition(NFATree&&, std::vector<std::shared_ptr<Vertex>> NFATree& operator=(const NFATree&) = delete;
start_vertexes, std::vector<std::shared_ptr<Vertex>> NFATree& operator=(NFATree&&) = default;
final_vertexes);
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);
void Composition(NFATree&&,
std::vector<size_t> start_vertexes,
std::vector<size_t> final_vertexes);
std::shared_ptr<Vertex> GetVertex(size_t number);
size_t GetCountVertexes() const;
const std::vector<size_t>& GetFinalVertexes() const;
const std::vector<size_t>& GetStartVertexes() const;
void Print() const;
private: private:
std::vector<std::shared_ptr<Vertex>> vertexes_; size_t count_vertexes_ = 0;
std::vector<std::weak_ptr<Vertex>> final_vertexes_; std::map<size_t, std::shared_ptr<Vertex>> vertexes_;
std::vector<std::weak_ptr<Vertex>> start_vertexes_; std::vector<size_t> final_vertexes_;
std::vector<size_t> start_vertexes_;
}; };
} }

View file

@ -1,23 +1,38 @@
#include "NFA/NFATree.hpp" #include "NFA/NFATree.hpp"
#include <algorithm> #include <algorithm>
#include <iostream>
namespace NFA { namespace NFA {
void NFATree::RemoveVertex(std::shared_ptr<Vertex> vertex) { size_t NFATree::AddNewVertex() {
RemoveFinalVertex(vertex); vertexes_[count_vertexes_] = std::make_shared<Vertex>();
RemoveStartVertex(vertex); vertexes_[count_vertexes_]->number_ = count_vertexes_;
for (size_t i = 0; i < vertexes_.size(); ++i) { return count_vertexes_++;
if (vertexes_[i] == vertex) {
std::swap(vertexes_[i], vertexes_.back());
vertexes_.pop_back();
break;
} }
void NFATree::AddFinalVertex(size_t number) {
if (!vertexes_[number]->is_final_) {
vertexes_[number]->is_final_ = true;
final_vertexes_.push_back(number);
} }
} }
void NFATree::RemoveFinalVertex(std::shared_ptr<Vertex> vertex) { void NFATree::AddStartVertex(size_t number) {
if (!vertexes_[number]->is_start_) {
vertexes_[number]->is_start_ = true;
start_vertexes_.push_back(number);
}
}
void NFATree::RemoveVertex(size_t number) {
RemoveFinalVertex(number);
RemoveStartVertex(number);
vertexes_.erase(number);
}
void NFATree::RemoveFinalVertex(size_t number) {
for (size_t i = 0; i < final_vertexes_.size(); ++i) { for (size_t i = 0; i < final_vertexes_.size(); ++i) {
if (final_vertexes_[i].lock() == vertex) { if (final_vertexes_[i] == number) {
final_vertexes_[i].lock()->SetFinal(false); vertexes_[number]->is_final_ = false;
std::swap(final_vertexes_[i], final_vertexes_.back()); std::swap(final_vertexes_[i], final_vertexes_.back());
final_vertexes_.pop_back(); final_vertexes_.pop_back();
break; break;
@ -25,10 +40,10 @@ void NFATree::RemoveFinalVertex(std::shared_ptr<Vertex> vertex) {
} }
} }
void NFATree::RemoveStartVertex(std::shared_ptr<Vertex> vertex) { void NFATree::RemoveStartVertex(size_t number) {
for (size_t i = 0; i < start_vertexes_.size(); ++i) { for (size_t i = 0; i < start_vertexes_.size(); ++i) {
if (start_vertexes_[i].lock() == vertex) { if (start_vertexes_[i] == number) {
start_vertexes_[i].lock()->SetStart(false); vertexes_[number]->is_start_ = false;
std::swap(start_vertexes_[i], start_vertexes_.back()); std::swap(start_vertexes_[i], start_vertexes_.back());
start_vertexes_.pop_back(); start_vertexes_.pop_back();
break; break;
@ -37,29 +52,79 @@ void NFATree::RemoveStartVertex(std::shared_ptr<Vertex> vertex) {
} }
void NFATree::Composition(NFATree&& tree, void NFATree::Composition(NFATree&& tree,
std::vector<std::shared_ptr<Vertex>> start_vertexes, std::vector<size_t> start_vertexes,
std::vector<std::shared_ptr<Vertex>> final_vertexes) { std::vector<size_t> final_vertexes) {
auto add_final_vertexes = tree.final_vertexes_; auto add_final_vertexes = tree.final_vertexes_;
auto add_start_vertexes = tree.start_vertexes_; auto add_start_vertexes = tree.start_vertexes_;
vertexes_.insert(vertexes_.begin(), tree.vertexes_.begin(), tree.vertexes_.end()); size_t new_count_vertexes = count_vertexes_;
for (auto& i: tree.vertexes_) {
new_count_vertexes = std::max(new_count_vertexes, i.first + count_vertexes_);
i.second->number_ += count_vertexes_;
for (auto& j: i.second->transitions) {
j.second += count_vertexes_;
}
vertexes_[i.second->number_] = std::move(i.second);
}
for (auto& i: add_start_vertexes) {
i += count_vertexes_;
}
for (auto& i: add_final_vertexes) {
i += count_vertexes_;
}
count_vertexes_ = new_count_vertexes;
for (auto& i: start_vertexes) { for (auto& i: start_vertexes) {
for (auto& j: add_start_vertexes) { for (auto& j: add_start_vertexes) {
i->transitions[' '].push_back(j); vertexes_[i]->transitions.emplace(' ', j);
} }
} }
for (auto& i: add_final_vertexes) { for (auto& i: add_final_vertexes) {
for (auto& j: final_vertexes) { for (auto& j: final_vertexes) {
i.lock()->transitions[' '].push_back(j); vertexes_[i]->transitions.emplace(' ', j);
} }
} }
for (auto& i: add_final_vertexes) { for (auto& i: add_final_vertexes) {
i.lock()->SetFinal(false); vertexes_[i]->is_final_ = false;
} }
for (auto& i: add_start_vertexes) { for (auto& i: add_start_vertexes) {
i.lock()->SetStart(false); vertexes_[i]->is_start_ = false;
} }
}
std::shared_ptr<NFATree::Vertex> NFATree::GetVertex(size_t number) {
if (vertexes_.count(number))
return vertexes_[number];
return nullptr;
}
size_t NFATree::GetCountVertexes() const {
return count_vertexes_;
}
const std::vector<size_t>& NFATree::GetFinalVertexes() const {
return final_vertexes_;
}
const std::vector<size_t>& NFATree::GetStartVertexes() const {
return start_vertexes_;
}
void NFATree::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;
} }
} }

View file

@ -15,11 +15,7 @@ bool Vertex::IsStart() const {
return is_start_; return is_start_;
} }
void Vertex::SetFinal(bool value) { size_t Vertex::GetNumber() const {
is_final_ = value; return number_;
}
void Vertex::SetStart(bool value) {
is_start_ = value;
} }

View file

@ -0,0 +1,50 @@
#include "converters/RegularToNFA.hpp"
#include "regular/RegularTree.hpp"
#include "NFA/NFATree.hpp"
using namespace NFA;
using namespace regular;
using Node = RegularTree::Node;
struct do_nothing_deleter{
template<typename T>
void operator()(T*) const {}
};
template<typename deleter>
NFATree RegularToNFA(std::unique_ptr<Node, deleter> node) {
NFATree result;
if (node->type == Node::Type::Word) {
auto last = result.AddNewVertex();
result.AddStartVertex(last);
for (char i: node->word) {
auto tmp = result.AddNewVertex();
result.GetVertex(last)->transitions.emplace(i, tmp);
last = tmp;
}
result.AddFinalVertex(last);
} 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) {
auto tmp = RegularToNFA(std::move(*it));
auto v = result.AddNewVertex();
result.Composition(std::move(tmp), result.GetFinalVertexes(), {v});
while (!result.GetFinalVertexes().empty()) {
result.RemoveFinalVertex(result.GetFinalVertexes()[0]);
}
result.AddFinalVertex(v);
}
} else if (node->type == Node::Type::Addition) {
// TODO
}
return result;
}
namespace converters {
NFATree RegularToNFA(RegularTree&& tree) {
const Node& root = tree.GetNode();
return RegularToNFA(std::unique_ptr<Node,
do_nothing_deleter>(&const_cast<Node&>(tree.GetNode())));
}
}

View file

@ -1,5 +1,6 @@
#include <iostream> #include <iostream>
#include "regular/RegularTree.hpp" #include "regular/RegularTree.hpp"
#include "converters/RegularToNFA.hpp"
int main() { int main() {
using namespace regular; using namespace regular;
@ -7,4 +8,12 @@ int main() {
std::cin >> str; std::cin >> str;
RegularTree reg_tree(str); RegularTree reg_tree(str);
reg_tree.Print(); reg_tree.Print();
auto NFA_tree = converters::RegularToNFA(std::move(reg_tree));
std::cout << std::endl;
NFA_tree.Print();
} }

View file

@ -16,6 +16,7 @@ void Node::Print() const {
} }
void Node::ParseCurrentType(const std::string_view regular) { void Node::ParseCurrentType(const std::string_view regular) {
std::cout << "# " << regular << std::endl;
const size_t n = regular.size(); const size_t n = regular.size();
children.clear(); children.clear();
word.clear(); word.clear();
@ -87,7 +88,7 @@ void Node::ParseCurrentType(const std::string_view regular) {
} else if (regular[i] == ')') { } else if (regular[i] == ')') {
--balance; --balance;
if (balance == 0) { if (balance == 0) {
AddChild(regular.substr(begin_child + 1, i - begin_child - 1)); AddChild(regular.substr(begin_child, i - begin_child));
begin_child = i + 1; begin_child = i + 1;
} }
} else if (i + 1 == n) { } else if (i + 1 == n) {