Many changes
This commit is contained in:
parent
45527d2c06
commit
32f8a3dcc6
|
@ -21,10 +21,21 @@ set(SOURCE_FILES
|
||||||
src/NFA/NFATree.cpp
|
src/NFA/NFATree.cpp
|
||||||
src/NFA/NFATreeVertex.cpp
|
src/NFA/NFATreeVertex.cpp
|
||||||
src/converters/RegularToNFA.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
|
set(TEST_FILES
|
||||||
tests/regular/parse_regular.cpp
|
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})
|
add_executable(Formalang src/main.cpp ${SOURCE_FILES})
|
||||||
|
|
68
include/DFA/DFAGraph.hpp
Normal file
68
include/DFA/DFAGraph.hpp
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace DFA {
|
||||||
|
class DFAGraph {
|
||||||
|
public:
|
||||||
|
class Vertex {
|
||||||
|
public:
|
||||||
|
Vertex(DFAGraph* owner);
|
||||||
|
|
||||||
|
bool IsFinal() const;
|
||||||
|
bool IsStart() const;
|
||||||
|
size_t GetNumber() const;
|
||||||
|
|
||||||
|
const std::map<char, size_t>& GetTransitions() const;
|
||||||
|
const std::map<char, size_t>& 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<char, size_t> transitions_;
|
||||||
|
std::map<char, size_t> 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<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;
|
||||||
|
bool Accepted(const std::string&) const;
|
||||||
|
private:
|
||||||
|
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_;
|
||||||
|
};
|
||||||
|
}
|
67
include/FDFA/FDFAGraph.hpp
Normal file
67
include/FDFA/FDFAGraph.hpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#pragma once
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace FDFA {
|
||||||
|
class FDFAGraph {
|
||||||
|
public:
|
||||||
|
class Vertex {
|
||||||
|
public:
|
||||||
|
Vertex(FDFAGraph* owner);
|
||||||
|
|
||||||
|
bool IsFinal() const;
|
||||||
|
bool IsStart() const;
|
||||||
|
size_t GetNumber() const;
|
||||||
|
|
||||||
|
const std::map<char, size_t>& GetTransitions() const;
|
||||||
|
const std::map<char, size_t>& 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<char, size_t> transitions_;
|
||||||
|
std::map<char, size_t> 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<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;
|
||||||
|
bool Accepted(const std::string&) const;
|
||||||
|
private:
|
||||||
|
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_;
|
||||||
|
};
|
||||||
|
}
|
|
@ -10,15 +10,24 @@ class NFATree {
|
||||||
public:
|
public:
|
||||||
class Vertex {
|
class Vertex {
|
||||||
public:
|
public:
|
||||||
Vertex();
|
Vertex(NFATree* owner);
|
||||||
|
|
||||||
bool IsFinal() const;
|
bool IsFinal() const;
|
||||||
bool IsStart() const;
|
bool IsStart() const;
|
||||||
size_t GetNumber() const;
|
size_t GetNumber() const;
|
||||||
|
|
||||||
std::multimap<char, size_t> transitions;
|
const std::map<char, std::set<size_t>>& GetTransitions() const;
|
||||||
|
const std::map<char, std::set<size_t>>& 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:
|
private:
|
||||||
Vertex(bool is_final, bool is_start);
|
NFATree* owner_;
|
||||||
|
std::map<char, std::set<size_t>> transitions_;
|
||||||
|
std::map<char, std::set<size_t>> back_transitions_;
|
||||||
|
|
||||||
size_t number_;
|
size_t number_;
|
||||||
bool is_final_ = false;
|
bool is_final_ = false;
|
||||||
|
@ -29,10 +38,10 @@ class NFATree {
|
||||||
|
|
||||||
NFATree() = default;
|
NFATree() = default;
|
||||||
NFATree(const NFATree&) = delete;
|
NFATree(const NFATree&) = delete;
|
||||||
NFATree(NFATree&&) = default;
|
NFATree(NFATree&&);
|
||||||
|
|
||||||
NFATree& operator=(const NFATree&) = delete;
|
NFATree& operator=(const NFATree&) = delete;
|
||||||
NFATree& operator=(NFATree&&) = default;
|
NFATree& operator=(NFATree&&);
|
||||||
|
|
||||||
size_t AddNewVertex();
|
size_t AddNewVertex();
|
||||||
void AddFinalVertex(size_t number);
|
void AddFinalVertex(size_t number);
|
||||||
|
|
10
include/converters/DFAToFDFA.hpp
Normal file
10
include/converters/DFAToFDFA.hpp
Normal file
|
@ -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<char>& alphabet);
|
||||||
|
// FDFAGraph DFAGraphToFDFAGraph(DFAGraph&&, const std::vector<char>& alphabet);
|
||||||
|
}
|
7
include/converters/DFAToMinDFA.hpp
Normal file
7
include/converters/DFAToMinDFA.hpp
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
#include "DFA/DFAGraph.hpp"
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
using namespace DFA;
|
||||||
|
DFAGraph DFAToMinDFA(DFAGraph&&);
|
||||||
|
}
|
8
include/converters/DFAToRegular.hpp
Normal file
8
include/converters/DFAToRegular.hpp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
#include "DFA/DFAGraph.hpp"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
using namespace DFA;
|
||||||
|
std::string DFAGraphToRegular(DFAGraph&&);
|
||||||
|
}
|
13
include/converters/NFAToDFA.hpp
Normal file
13
include/converters/NFAToDFA.hpp
Normal file
|
@ -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&&);
|
||||||
|
}
|
10
include/converters/RegularToNFA.hpp
Normal file
10
include/converters/RegularToNFA.hpp
Normal file
|
@ -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&&);
|
||||||
|
}
|
98
src/DFA/DFAGraph.cpp
Normal file
98
src/DFA/DFAGraph.cpp
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
#include "DFA/DFAGraph.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace DFA {
|
||||||
|
size_t DFAGraph::AddNewVertex() {
|
||||||
|
vertexes_[count_vertexes_] = std::make_shared<Vertex>(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::Vertex> 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<size_t>& DFAGraph::GetFinalVertexes() const {
|
||||||
|
return final_vertexes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<size_t>& 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<const Vertex> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
58
src/DFA/DFAGraphVertex.cpp
Normal file
58
src/DFA/DFAGraphVertex.cpp
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#include "DFA/DFAGraph.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
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<char, size_t>& Vertex::GetTransitions() const {
|
||||||
|
return transitions_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::map<char, size_t>& 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_);
|
||||||
|
}
|
||||||
|
}
|
98
src/FDFA/FDFAGraph.cpp
Normal file
98
src/FDFA/FDFAGraph.cpp
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
#include "FDFA/FDFAGraph.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace FDFA {
|
||||||
|
size_t FDFAGraph::AddNewVertex() {
|
||||||
|
vertexes_[count_vertexes_] = std::make_shared<Vertex>(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::Vertex> 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<size_t>& FDFAGraph::GetFinalVertexes() const {
|
||||||
|
return final_vertexes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<size_t>& 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<const Vertex> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
58
src/FDFA/FDFAGraphVertex.cpp
Normal file
58
src/FDFA/FDFAGraphVertex.cpp
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#include "FDFA/FDFAGraph.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
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<char, size_t>& Vertex::GetTransitions() const {
|
||||||
|
return transitions_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::map<char, size_t>& 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_);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,8 +3,33 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace NFA {
|
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() {
|
size_t NFATree::AddNewVertex() {
|
||||||
vertexes_[count_vertexes_] = std::make_shared<Vertex>();
|
vertexes_[count_vertexes_] = std::make_shared<Vertex>(this);
|
||||||
vertexes_[count_vertexes_]->number_ = count_vertexes_;
|
vertexes_[count_vertexes_]->number_ = count_vertexes_;
|
||||||
return count_vertexes_++;
|
return count_vertexes_++;
|
||||||
}
|
}
|
||||||
|
@ -60,11 +85,24 @@ void NFATree::Composition(NFATree&& tree,
|
||||||
size_t new_count_vertexes = count_vertexes_;
|
size_t new_count_vertexes = count_vertexes_;
|
||||||
|
|
||||||
for (auto& i: tree.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_;
|
i.second->number_ += count_vertexes_;
|
||||||
for (auto& j: i.second->transitions) {
|
std::map<char, std::set<size_t>> new_transitions;
|
||||||
j.second += count_vertexes_;
|
for (auto& j: i.second->transitions_) {
|
||||||
|
for (auto& k: j.second) {
|
||||||
|
new_transitions[j.first].insert(k + count_vertexes_);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
std::map<char, std::set<size_t>> 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);
|
vertexes_[i.second->number_] = std::move(i.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,12 +117,14 @@ void NFATree::Composition(NFATree&& tree,
|
||||||
|
|
||||||
for (auto& i: start_vertexes) {
|
for (auto& i: start_vertexes) {
|
||||||
for (auto& j: add_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& i: add_final_vertexes) {
|
||||||
for (auto& j: 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) {
|
for (auto& i: add_final_vertexes) {
|
||||||
|
@ -119,12 +159,13 @@ void NFATree::Print() const {
|
||||||
i.second->is_start_ << std::endl;
|
i.second->is_start_ << std::endl;
|
||||||
}
|
}
|
||||||
for (auto& i: vertexes_) {
|
for (auto& i: vertexes_) {
|
||||||
for (auto& j: i.second->transitions) {
|
for (auto& j: i.second->transitions_) {
|
||||||
std::cout << i.second->number_ << "->" << j.second << " <" << j.first << ">" <<
|
for (auto k: j.second) {
|
||||||
|
std::cout << i.second->number_ << "->" << k << " <" << j.first << ">" <<
|
||||||
std::endl;
|
std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
#include "NFA/NFATree.hpp"
|
#include "NFA/NFATree.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using Vertex = NFA::NFATree::Vertex;
|
using Vertex = NFA::NFATree::Vertex;
|
||||||
|
|
||||||
Vertex::Vertex() {}
|
Vertex::Vertex(NFATree* owner) : owner_(owner) {}
|
||||||
|
|
||||||
Vertex::Vertex(bool is_final, bool is_start) : is_final_(is_final),
|
|
||||||
is_start_(is_start) {}
|
|
||||||
|
|
||||||
bool Vertex::IsFinal() const {
|
bool Vertex::IsFinal() const {
|
||||||
return is_final_;
|
return is_final_;
|
||||||
|
@ -19,3 +17,47 @@ size_t Vertex::GetNumber() const {
|
||||||
return number_;
|
return number_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::map<char, std::set<size_t>>& Vertex::GetTransitions() const {
|
||||||
|
return transitions_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::map<char, std::set<size_t>>& 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_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
90
src/converters/DFAToFDFA.cpp
Normal file
90
src/converters/DFAToFDFA.cpp
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#include "converters/DFAToFDFA.hpp"
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
DFAGraph DFAGraphToFDFAGraph(DFAGraph&& graph, const std::vector<char>& alphabet) {
|
||||||
|
DFAGraph result;
|
||||||
|
const int n = graph.GetCountVertexes();
|
||||||
|
std::map<size_t, size_t> 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<char>& alphabet) {
|
||||||
|
FDFAGraph result;
|
||||||
|
const int n = graph.GetCountVertexes();
|
||||||
|
std::map<size_t, size_t> 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;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
111
src/converters/DFAToMinDFA.cpp
Normal file
111
src/converters/DFAToMinDFA.cpp
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#include "converters/DFAToMinDFA.hpp"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
DFAGraph DFAToMinDFA(DFAGraph&& graph) {
|
||||||
|
const int n = graph.GetCountVertexes();
|
||||||
|
DFAGraph result;
|
||||||
|
|
||||||
|
std::vector<char> alphabet;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::set<char> salphabet;
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
for (auto i: graph.GetVertex(i)->GetTransitions()) {
|
||||||
|
salphabet.insert(i.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alphabet = std::vector<char>(salphabet.begin(), salphabet.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<std::vector<size_t>>> table(n,
|
||||||
|
std::vector<std::vector<size_t>>(n, std::vector<size_t>(alphabet.size() + 1)));
|
||||||
|
|
||||||
|
{
|
||||||
|
std::vector<std::vector<size_t>>& 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<std::vector<size_t>>& prev_layer(table[number_layer - 1]);
|
||||||
|
std::vector<std::vector<size_t>>& 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<std::vector<size_t>>& 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<size_t, size_t> 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;
|
||||||
|
}
|
||||||
|
}
|
126
src/converters/DFAToRegular.cpp
Normal file
126
src/converters/DFAToRegular.cpp
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
#include "converters/DFAToRegular.hpp"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
std::string DFAGraphToRegular(DFAGraph&& graph) {
|
||||||
|
const size_t n = graph.GetCountVertexes() + 1;
|
||||||
|
std::string result = "";
|
||||||
|
|
||||||
|
std::vector<std::vector<std::set<std::string>>> transitions(n,
|
||||||
|
std::vector<std::set<std::string>>(n));
|
||||||
|
|
||||||
|
std::map<size_t, size_t> 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<std::vector<std::set<std::string>>> new_transitions(n,
|
||||||
|
std::vector<std::set<std::string>>(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;
|
||||||
|
}
|
||||||
|
}
|
293
src/converters/NFAToDFA.cpp
Normal file
293
src/converters/NFAToDFA.cpp
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
#include "converters/NFAToDFA.hpp"
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
/*
|
||||||
|
OLD version
|
||||||
|
|
||||||
|
|
||||||
|
NFATree AddAllEpsilonTransitions(NFATree&& tree) {
|
||||||
|
// Algorithm from 2-sat
|
||||||
|
const int n = tree.GetCountVertexes();
|
||||||
|
std::vector<bool> used(n, false);
|
||||||
|
std::vector<int> component(n, -1);
|
||||||
|
std::vector<int> order;
|
||||||
|
|
||||||
|
std::function<void(int)> 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<void(int, int)> 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<std::pair<int, int>> connectivity_components;
|
||||||
|
|
||||||
|
used.assign(n, false);
|
||||||
|
std::vector<std::set<int>> connectivity_from(current_component);
|
||||||
|
|
||||||
|
std::function<void(int)> 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<bool> used(n, false);
|
||||||
|
|
||||||
|
std::function<void(int, int)> 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<std::pair<std::set<size_t>, char>, std::set<size_t>> transitions;
|
||||||
|
std::map<std::set<size_t>, size_t> number_vertex_in_result_tree;
|
||||||
|
std::queue<std::set<size_t>> queue;
|
||||||
|
|
||||||
|
std::set<char> 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<size_t> 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<int, int> 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
#include "converters/RegularToNFA.hpp"
|
#include "converters/RegularToNFA.hpp"
|
||||||
#include "regular/RegularTree.hpp"
|
#include "regular/RegularTree.hpp"
|
||||||
#include "NFA/NFATree.hpp"
|
#include "NFA/NFATree.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace NFA;
|
using namespace NFA;
|
||||||
using namespace regular;
|
using namespace regular;
|
||||||
|
@ -15,14 +16,21 @@ template<typename deleter>
|
||||||
NFATree RegularToNFA(std::unique_ptr<Node, deleter> node) {
|
NFATree RegularToNFA(std::unique_ptr<Node, deleter> node) {
|
||||||
NFATree result;
|
NFATree result;
|
||||||
if (node->type == Node::Type::Word) {
|
if (node->type == Node::Type::Word) {
|
||||||
auto last = result.AddNewVertex();
|
auto end = result.AddNewVertex();
|
||||||
result.AddStartVertex(last);
|
auto start = end;
|
||||||
|
result.AddStartVertex(end);
|
||||||
for (char i: node->word) {
|
for (char i: node->word) {
|
||||||
auto tmp = result.AddNewVertex();
|
auto tmp = result.AddNewVertex();
|
||||||
result.GetVertex(last)->transitions.emplace(i, tmp);
|
result.GetVertex(end)->AddEdge(i, tmp);
|
||||||
last = 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) {
|
} else if (node->type == Node::Type::Concatenation) {
|
||||||
result = RegularToNFA(std::move(node->children[0]));
|
result = RegularToNFA(std::move(node->children[0]));
|
||||||
for (auto it = node->children.begin() + 1; it != node->children.end(); ++it) {
|
for (auto it = node->children.begin() + 1; it != node->children.end(); ++it) {
|
||||||
|
@ -34,9 +42,39 @@ NFATree RegularToNFA(std::unique_ptr<Node, deleter> node) {
|
||||||
}
|
}
|
||||||
result.AddFinalVertex(v);
|
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) {
|
} 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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
156
src/main.cpp
156
src/main.cpp
|
@ -1,9 +1,163 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <cassert>
|
||||||
#include "regular/RegularTree.hpp"
|
#include "regular/RegularTree.hpp"
|
||||||
#include "converters/RegularToNFA.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() {
|
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::string str;
|
||||||
std::cin >> str;
|
std::cin >> str;
|
||||||
RegularTree reg_tree(str);
|
RegularTree reg_tree(str);
|
||||||
|
|
|
@ -16,7 +16,6 @@ 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();
|
||||||
|
@ -82,8 +81,8 @@ void Node::ParseCurrentType(const std::string_view regular) {
|
||||||
if (balance == 1) {
|
if (balance == 1) {
|
||||||
if (begin_child < i) {
|
if (begin_child < i) {
|
||||||
AddChild(regular.substr(begin_child, i - begin_child));
|
AddChild(regular.substr(begin_child, i - begin_child));
|
||||||
begin_child = i + 1;
|
|
||||||
}
|
}
|
||||||
|
begin_child = i + 1;
|
||||||
}
|
}
|
||||||
} else if (regular[i] == ')') {
|
} else if (regular[i] == ')') {
|
||||||
--balance;
|
--balance;
|
||||||
|
@ -95,13 +94,28 @@ void Node::ParseCurrentType(const std::string_view regular) {
|
||||||
if (balance != 0) {
|
if (balance != 0) {
|
||||||
throw std::logic_error("invalid regular");
|
throw std::logic_error("invalid regular");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (children.size() == 0) {
|
if (children.size() == 0) {
|
||||||
type = Type::Word;
|
type = Type::Word;
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
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 {
|
} else {
|
||||||
AddChild(regular.substr(begin_child, i - begin_child + 1));
|
AddChild(regular.substr(begin_child, i - begin_child + 1));
|
||||||
begin_child = i + 1;
|
begin_child = i + 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (balance == 0) {
|
} else if (balance == 0) {
|
||||||
if (regular[i] == '+') {
|
if (regular[i] == '+') {
|
||||||
if (begin_child < i) {
|
if (begin_child < i) {
|
||||||
|
|
202
tests/DFAToRegular/DFAToRegular.cpp
Normal file
202
tests/DFAToRegular/DFAToRegular.cpp
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <random>
|
||||||
|
#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<char> 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<char> 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<char> 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<char> 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));
|
||||||
|
}
|
||||||
|
}
|
111
tests/NFAToDFA/check_equivalence.cpp
Normal file
111
tests/NFAToDFA/check_equivalence.cpp
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <random>
|
||||||
|
#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<char> 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));
|
||||||
|
}
|
||||||
|
}
|
151
tests/regularToDFA/regularToDFA.cpp
Normal file
151
tests/regularToDFA/regularToDFA.cpp
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <random>
|
||||||
|
#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<char> 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<char> 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<char> 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<char> 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));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue