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/NFA/NFATree.cpp
src/NFA/NFATreeVertex.cpp
src/converters/RegularToNFA.cpp
)
set(TEST_FILES

View file

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

View file

@ -1,23 +1,38 @@
#include "NFA/NFATree.hpp"
#include <algorithm>
#include <iostream>
namespace NFA {
void NFATree::RemoveVertex(std::shared_ptr<Vertex> vertex) {
RemoveFinalVertex(vertex);
RemoveStartVertex(vertex);
for (size_t i = 0; i < vertexes_.size(); ++i) {
if (vertexes_[i] == vertex) {
std::swap(vertexes_[i], vertexes_.back());
vertexes_.pop_back();
break;
}
size_t NFATree::AddNewVertex() {
vertexes_[count_vertexes_] = std::make_shared<Vertex>();
vertexes_[count_vertexes_]->number_ = count_vertexes_;
return count_vertexes_++;
}
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) {
if (final_vertexes_[i].lock() == vertex) {
final_vertexes_[i].lock()->SetFinal(false);
if (final_vertexes_[i] == number) {
vertexes_[number]->is_final_ = false;
std::swap(final_vertexes_[i], final_vertexes_.back());
final_vertexes_.pop_back();
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) {
if (start_vertexes_[i].lock() == vertex) {
start_vertexes_[i].lock()->SetStart(false);
if (start_vertexes_[i] == number) {
vertexes_[number]->is_start_ = false;
std::swap(start_vertexes_[i], start_vertexes_.back());
start_vertexes_.pop_back();
break;
@ -37,29 +52,79 @@ void NFATree::RemoveStartVertex(std::shared_ptr<Vertex> vertex) {
}
void NFATree::Composition(NFATree&& tree,
std::vector<std::shared_ptr<Vertex>> start_vertexes,
std::vector<std::shared_ptr<Vertex>> final_vertexes) {
std::vector<size_t> start_vertexes,
std::vector<size_t> final_vertexes) {
auto add_final_vertexes = tree.final_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& j: add_start_vertexes) {
i->transitions[' '].push_back(j);
vertexes_[i]->transitions.emplace(' ', j);
}
}
for (auto& i: add_final_vertexes) {
for (auto& j: final_vertexes) {
i.lock()->transitions[' '].push_back(j);
vertexes_[i]->transitions.emplace(' ', j);
}
}
for (auto& i: add_final_vertexes) {
i.lock()->SetFinal(false);
vertexes_[i]->is_final_ = false;
}
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_;
}
void Vertex::SetFinal(bool value) {
is_final_ = value;
}
void Vertex::SetStart(bool value) {
is_start_ = value;
size_t Vertex::GetNumber() const {
return number_;
}

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 "regular/RegularTree.hpp"
#include "converters/RegularToNFA.hpp"
int main() {
using namespace regular;
@ -7,4 +8,12 @@ int main() {
std::cin >> str;
RegularTree reg_tree(str);
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) {
std::cout << "# " << regular << std::endl;
const size_t n = regular.size();
children.clear();
word.clear();
@ -87,7 +88,7 @@ void Node::ParseCurrentType(const std::string_view regular) {
} else if (regular[i] == ')') {
--balance;
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;
}
} else if (i + 1 == n) {