Compare commits
20 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
687e6adb3b | ||
![]() |
59521e3be2 | ||
![]() |
34560d3628 | ||
![]() |
04109bd54b | ||
![]() |
346f0016a5 | ||
![]() |
40b634b722 | ||
![]() |
1aed271643 | ||
![]() |
7023d46c56 | ||
![]() |
f715234f41 | ||
![]() |
124a6c17b1 | ||
![]() |
0947eeac5d | ||
![]() |
aad17d8c8c | ||
![]() |
1fd4158840 | ||
![]() |
32f8a3dcc6 | ||
![]() |
45527d2c06 | ||
![]() |
82822d316f | ||
![]() |
65fffffe8e | ||
![]() |
8e014193cc | ||
![]() |
f3848d88b3 | ||
![]() |
a1843f4898 |
|
@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.10)
|
||||||
project("Formalang")
|
project("Formalang")
|
||||||
|
|
||||||
# set(CMAKE_CXX_FLAGS "-O3")
|
# set(CMAKE_CXX_FLAGS "-O3")
|
||||||
|
# set(CMAKE_CXX_FLAGS "-O0 --coverage -ftest-coverage -fprofile-arcs")
|
||||||
|
|
||||||
find_package(GTest REQUIRED)
|
find_package(GTest REQUIRED)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
@ -10,19 +11,38 @@ find_package(Threads REQUIRED)
|
||||||
include_directories(
|
include_directories(
|
||||||
"include"
|
"include"
|
||||||
${GTEST_INCLUDE_DIRS}
|
${GTEST_INCLUDE_DIRS}
|
||||||
${Boost_INCLUDE_DIR}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
set(SOURCE_FILES)
|
set(SOURCE_FILES
|
||||||
|
src/regular/RegularTree.cpp
|
||||||
|
src/regular/RegularTreeNode.cpp
|
||||||
|
src/NFA/NFAGraph.cpp
|
||||||
|
src/NFA/NFAGraphVertex.cpp
|
||||||
|
src/converters/RegularToNFA.cpp
|
||||||
|
src/converters/NFAToDFA.cpp
|
||||||
|
src/DFA/DFAGraph.cpp
|
||||||
|
src/DFA/DFAGraphVertex.cpp
|
||||||
|
src/converters/DFAToFDFA.cpp
|
||||||
|
src/converters/DFAToMinDFA.cpp
|
||||||
|
src/converters/DFAToRegular.cpp
|
||||||
|
src/converters/InvertFDFA.cpp
|
||||||
|
)
|
||||||
|
|
||||||
set(TEST_FILES)
|
set(TEST_FILES
|
||||||
|
tests/regular/ParseRegular.cpp
|
||||||
|
tests/NFAToDFA/CheckEquivalence.cpp
|
||||||
|
tests/regularToDFA/RegularToDFA.cpp
|
||||||
|
tests/DFAToRegular/DFAToRegular.cpp
|
||||||
|
tests/invertFDFA/InvertFDFA.cpp
|
||||||
|
tests/DFAToRegular/DFAToRegular2.cpp
|
||||||
|
tests/DFAToMinDFA/CountSizesMinDFA.cpp
|
||||||
|
tests/GenericTest/GenericTest1.cpp
|
||||||
|
)
|
||||||
|
|
||||||
add_executable(Formalang src/main.cpp ${SOURCE_FILES})
|
add_executable(Formalang src/main.cpp ${SOURCE_FILES})
|
||||||
|
|
||||||
add_executable(Tests tests/test_main.cpp ${TEST_FILES} ${SOURCE_FILES})
|
add_executable(Tests tests/MainTest.cpp ${TEST_FILES} ${SOURCE_FILES})
|
||||||
|
|
||||||
target_link_libraries(Tests ${GTEST_LIBRARIES} Threads::Threads)
|
target_link_libraries(Tests ${GTEST_LIBRARIES} Threads::Threads)
|
||||||
target_link_libraries(Formalang Threads::Threads)
|
|
||||||
|
|
||||||
|
|
43
README.md
Normal file
43
README.md
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
# Formalang
|
||||||
|
```c++
|
||||||
|
#include "regular/RegularTree.hpp"
|
||||||
|
#include "NFA/NFAGraph.hpp"
|
||||||
|
#include "DFA/DFAGraph.hpp"
|
||||||
|
#include "converters/RegularToNFA.hpp"
|
||||||
|
#include "converters/NFAToDFA.hpp"
|
||||||
|
#include "converters/DFAToFDFA.hpp"
|
||||||
|
#include "converters/DFAToMinDFA.hpp"
|
||||||
|
#include "converters/DFAToRegular.hpp"
|
||||||
|
#include "converters/InvertFDFA.hpp"
|
||||||
|
|
||||||
|
using namespace regular;
|
||||||
|
using namespace NFA;
|
||||||
|
using namespace DFA;
|
||||||
|
using namespace converters;
|
||||||
|
```
|
||||||
|
так можно подключить все что есть в моей программе.
|
||||||
|
```c++
|
||||||
|
RegularTree r("a*"); // Регулярное выражение
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r)); // В НКА
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); // В ДКА
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); // Минимизация
|
||||||
|
DFA_graph.Print(); // Мой вывод
|
||||||
|
DFA_graph.CreateDotFile("2.dot"); // Вывод в dot файл
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph)); // В регулярку
|
||||||
|
```
|
||||||
|
Такой вывод в регулярку как показано в прошлом примере сделает много лишних скобок, если мы хотим привести к более нормальному виду, то можно сделать так
|
||||||
|
```c++
|
||||||
|
RegularTree(reg).ToString() // Получится более красивая регулярка
|
||||||
|
```
|
||||||
|
Про сами регулярки + * - это плюс и звезда Клини. Их можно писать после слов, или после скобок.
|
||||||
|
abacaba\* ~ (abacaba)\*. a(b)a\* ~ a(b)(a)\*. Для сложения языков используется |. Символом пустого слова является пробел.
|
||||||
|
|
||||||
|
Очень важное отличие, что у меня + \* привязываются не к букве, а к слову(например aba* это (aba)\*, а не ab(a)\* как вы ожидаете), это значительное отличие от существующих регулярок, но .ToString у RegularTree всегда + \* выдаст строку у которой перед + \* будет стоять скобочка
|
||||||
|
|
||||||
|
Примеры регулярок
|
||||||
|
|
||||||
|
a*
|
||||||
|
|
||||||
|
a(b)+a
|
||||||
|
|
||||||
|
(a|b)*
|
71
include/DFA/DFAGraph.hpp
Normal file
71
include/DFA/DFAGraph.hpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#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&&);
|
||||||
|
|
||||||
|
DFAGraph& operator=(const DFAGraph&) = delete;
|
||||||
|
DFAGraph& operator=(DFAGraph&&);
|
||||||
|
|
||||||
|
size_t AddNewVertex();
|
||||||
|
void AddFinalVertex(size_t number);
|
||||||
|
void SetStartVertex(size_t number);
|
||||||
|
|
||||||
|
void RemoveVertex(size_t number);
|
||||||
|
void RemoveFinalVertex(size_t number);
|
||||||
|
void RemoveStartVertex(size_t number);
|
||||||
|
|
||||||
|
Vertex& GetVertex(size_t number);
|
||||||
|
bool NotExistVertex(size_t number);
|
||||||
|
|
||||||
|
size_t GetCountVertexes() const;
|
||||||
|
size_t GetReallyCountVertexes() const;
|
||||||
|
const std::vector<size_t>& GetFinalVertexes() const;
|
||||||
|
size_t GetStartVertex() const;
|
||||||
|
|
||||||
|
void Print() const;
|
||||||
|
bool Accepted(const std::string&) const;
|
||||||
|
void CreateDotFile(const std::string& filename) const;
|
||||||
|
private:
|
||||||
|
size_t count_vertexes_ = 0;
|
||||||
|
std::map<size_t, Vertex> vertexes_;
|
||||||
|
std::vector<size_t> final_vertexes_;
|
||||||
|
size_t start_vertex_ = -1;
|
||||||
|
};
|
||||||
|
}
|
74
include/NFA/NFAGraph.hpp
Normal file
74
include/NFA/NFAGraph.hpp
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace NFA {
|
||||||
|
class NFAGraph {
|
||||||
|
public:
|
||||||
|
class Vertex {
|
||||||
|
public:
|
||||||
|
Vertex(NFAGraph* owner);
|
||||||
|
|
||||||
|
bool IsFinal() const;
|
||||||
|
bool IsStart() const;
|
||||||
|
size_t GetNumber() const;
|
||||||
|
|
||||||
|
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(NFAGraph* owner);
|
||||||
|
void SetFinal(bool status);
|
||||||
|
void SetStart(bool status);
|
||||||
|
private:
|
||||||
|
NFAGraph* owner_;
|
||||||
|
std::map<char, std::set<size_t>> transitions_;
|
||||||
|
std::map<char, std::set<size_t>> back_transitions_;
|
||||||
|
|
||||||
|
size_t number_;
|
||||||
|
bool is_final_ = false;
|
||||||
|
bool is_start_ = false;
|
||||||
|
|
||||||
|
friend class NFAGraph;
|
||||||
|
};
|
||||||
|
|
||||||
|
NFAGraph() = default;
|
||||||
|
NFAGraph(const NFAGraph&) = delete;
|
||||||
|
NFAGraph(NFAGraph&&);
|
||||||
|
|
||||||
|
NFAGraph& operator=(const NFAGraph&) = delete;
|
||||||
|
NFAGraph& operator=(NFAGraph&&);
|
||||||
|
|
||||||
|
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(NFAGraph&&,
|
||||||
|
std::vector<size_t> start_vertexes,
|
||||||
|
std::vector<size_t> final_vertexes);
|
||||||
|
|
||||||
|
Vertex& GetVertex(size_t number);
|
||||||
|
bool NotExistVertex(size_t number);
|
||||||
|
|
||||||
|
size_t GetCountVertexes() const;
|
||||||
|
size_t GetReallyCountVertexes() const;
|
||||||
|
const std::vector<size_t>& GetFinalVertexes() const;
|
||||||
|
const std::vector<size_t>& GetStartVertexes() const;
|
||||||
|
|
||||||
|
void Print() const;
|
||||||
|
void CreateDotFile(const std::string& filename) const;
|
||||||
|
private:
|
||||||
|
size_t count_vertexes_ = 0;
|
||||||
|
std::map<size_t, Vertex> vertexes_;
|
||||||
|
std::vector<size_t> final_vertexes_;
|
||||||
|
std::vector<size_t> start_vertexes_;
|
||||||
|
};
|
||||||
|
}
|
7
include/converters/DFAToFDFA.hpp
Normal file
7
include/converters/DFAToFDFA.hpp
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
#include "DFA/DFAGraph.hpp"
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
using namespace DFA;
|
||||||
|
DFAGraph 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 DFAGraphToMinDFAGraph(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&&);
|
||||||
|
}
|
7
include/converters/InvertFDFA.hpp
Normal file
7
include/converters/InvertFDFA.hpp
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
#include "DFA/DFAGraph.hpp"
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
using namespace DFA;
|
||||||
|
DFAGraph InvertFDFAGraph(DFAGraph&&);
|
||||||
|
}
|
13
include/converters/NFAToDFA.hpp
Normal file
13
include/converters/NFAToDFA.hpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
#include "NFA/NFAGraph.hpp"
|
||||||
|
#include "DFA/DFAGraph.hpp"
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
using namespace NFA;
|
||||||
|
using namespace DFA;
|
||||||
|
NFAGraph AddAllEpsilonTransitions(NFAGraph&&);
|
||||||
|
NFAGraph AddAllPossibleFinalVertexes(NFAGraph&&);
|
||||||
|
NFAGraph DeleteEpsilonTransitions(NFAGraph&&);
|
||||||
|
NFAGraph DeleteTransitionsByOneLetter(NFAGraph&&);
|
||||||
|
DFAGraph NFAGraphToDFAGraph(NFAGraph&&);
|
||||||
|
}
|
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/NFAGraph.hpp"
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
using namespace NFA;
|
||||||
|
using namespace regular;
|
||||||
|
|
||||||
|
NFAGraph RegularToNFAGraph(RegularTree&&);
|
||||||
|
}
|
44
include/regular/RegularTree.hpp
Normal file
44
include/regular/RegularTree.hpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace regular {
|
||||||
|
class RegularTree {
|
||||||
|
public:
|
||||||
|
class Node {
|
||||||
|
public:
|
||||||
|
enum class Type {
|
||||||
|
Addition, Concatenation, Word
|
||||||
|
};
|
||||||
|
enum class Modifier {
|
||||||
|
Plus, Star, None
|
||||||
|
};
|
||||||
|
|
||||||
|
Node();
|
||||||
|
Node(Type);
|
||||||
|
|
||||||
|
void Parse(const std::string&);
|
||||||
|
void Print() const;
|
||||||
|
std::vector<std::unique_ptr<Node>> children;
|
||||||
|
std::string word;
|
||||||
|
Type type;
|
||||||
|
Modifier modifier = Modifier::None;
|
||||||
|
std::string ToString() const;
|
||||||
|
private:
|
||||||
|
void ParseCurrentType(const std::string_view);
|
||||||
|
void Compression();
|
||||||
|
void Compression2();
|
||||||
|
void Print(int nesting_level) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
RegularTree(const std::string&);
|
||||||
|
const Node& GetNode() const;
|
||||||
|
void Print() const;
|
||||||
|
std::string ToString() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Node node_;
|
||||||
|
};
|
||||||
|
}
|
149
src/DFA/DFAGraph.cpp
Normal file
149
src/DFA/DFAGraph.cpp
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
#include "DFA/DFAGraph.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
extern std::map<size_t, std::string> names;
|
||||||
|
namespace DFA {
|
||||||
|
DFAGraph::DFAGraph(DFAGraph&& another) {
|
||||||
|
std::swap(count_vertexes_, another.count_vertexes_);
|
||||||
|
std::swap(vertexes_, another.vertexes_);
|
||||||
|
std::swap(final_vertexes_, another.final_vertexes_);
|
||||||
|
std::swap(start_vertex_, another.start_vertex_);
|
||||||
|
|
||||||
|
for (auto& i: vertexes_)
|
||||||
|
i.second.owner_ = this;
|
||||||
|
for (auto& i: another.vertexes_)
|
||||||
|
i.second.owner_ = &another;
|
||||||
|
}
|
||||||
|
|
||||||
|
DFAGraph& DFAGraph::operator=(DFAGraph&& another) {
|
||||||
|
std::swap(count_vertexes_, another.count_vertexes_);
|
||||||
|
std::swap(vertexes_, another.vertexes_);
|
||||||
|
std::swap(final_vertexes_, another.final_vertexes_);
|
||||||
|
std::swap(start_vertex_, another.start_vertex_);
|
||||||
|
|
||||||
|
for (auto& i: vertexes_)
|
||||||
|
i.second.owner_ = this;
|
||||||
|
for (auto& i: another.vertexes_)
|
||||||
|
i.second.owner_ = &another;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
size_t DFAGraph::AddNewVertex() {
|
||||||
|
vertexes_.emplace(count_vertexes_, this);
|
||||||
|
GetVertex(count_vertexes_).number_ = count_vertexes_;
|
||||||
|
return count_vertexes_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DFAGraph::AddFinalVertex(size_t number) {
|
||||||
|
if (!GetVertex(number).is_final_) {
|
||||||
|
GetVertex(number).is_final_ = true;
|
||||||
|
final_vertexes_.push_back(number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DFAGraph::SetStartVertex(size_t number) {
|
||||||
|
if (!GetVertex(number).is_start_) {
|
||||||
|
GetVertex(number).is_start_ = true;
|
||||||
|
start_vertex_ = number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DFAGraph::RemoveVertex(size_t number) {
|
||||||
|
RemoveFinalVertex(number);
|
||||||
|
RemoveStartVertex(number);
|
||||||
|
vertexes_.erase(number);
|
||||||
|
if (number == count_vertexes_ - 1) count_vertexes_--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DFAGraph::RemoveFinalVertex(size_t number) {
|
||||||
|
for (size_t i = 0; i < final_vertexes_.size(); ++i) {
|
||||||
|
if (final_vertexes_[i] == number) {
|
||||||
|
GetVertex(number).is_final_ = false;
|
||||||
|
std::swap(final_vertexes_[i], final_vertexes_.back());
|
||||||
|
final_vertexes_.pop_back();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DFAGraph::RemoveStartVertex(size_t number) {
|
||||||
|
if (start_vertex_ == number) {
|
||||||
|
start_vertex_ = -1;
|
||||||
|
GetVertex(number).is_start_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DFAGraph::Vertex& DFAGraph::GetVertex(size_t number) {
|
||||||
|
if (!NotExistVertex(number))
|
||||||
|
return vertexes_.at(number);
|
||||||
|
throw std::out_of_range("This vertex don't exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DFAGraph::NotExistVertex(size_t number) {
|
||||||
|
return !vertexes_.count(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DFAGraph::GetCountVertexes() const {
|
||||||
|
return count_vertexes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DFAGraph::GetReallyCountVertexes() const {
|
||||||
|
return vertexes_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<size_t>& DFAGraph::GetFinalVertexes() const {
|
||||||
|
return final_vertexes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DFAGraph::GetStartVertex() const {
|
||||||
|
return start_vertex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
size_t current = start_vertex_;
|
||||||
|
for (auto i: str) {
|
||||||
|
if (vertexes_.at(current).GetTransitions().count(i)) {
|
||||||
|
current = vertexes_.at(vertexes_.at(current).GetTransitions().at(i)).GetNumber();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vertexes_.at(current).IsFinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DFAGraph::CreateDotFile(const std::string& filename) const {
|
||||||
|
std::ofstream out(filename);
|
||||||
|
out << "digraph G {\n";
|
||||||
|
|
||||||
|
for (auto& i: vertexes_) {
|
||||||
|
for (auto& j: i.second.transitions_) {
|
||||||
|
out << "\"" << i.first << "\"" << "->\"" << j.second << "\"[label=" << j.first << "]\n";
|
||||||
|
}
|
||||||
|
if (i.second.IsStart() && i.second.IsFinal()) {
|
||||||
|
out << " \"" << i.first << "\" [shape=star];\n";
|
||||||
|
} else if (i.second.IsStart()) {
|
||||||
|
out << " \"" << i.first << "\" [shape=rarrow];\n";
|
||||||
|
} else if (i.second.IsFinal()) {
|
||||||
|
out << " \"" << i.first << "\" [shape=Msquare];\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out << "}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
57
src/DFA/DFAGraphVertex.cpp
Normal file
57
src/DFA/DFAGraphVertex.cpp
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#include "DFA/DFAGraph.hpp"
|
||||||
|
|
||||||
|
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_->SetStartVertex(number_);
|
||||||
|
else
|
||||||
|
owner_->RemoveStartVertex(number_);
|
||||||
|
}
|
||||||
|
}
|
205
src/NFA/NFAGraph.cpp
Normal file
205
src/NFA/NFAGraph.cpp
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
#include "NFA/NFAGraph.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace NFA {
|
||||||
|
NFAGraph::NFAGraph(NFAGraph&& 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
NFAGraph& NFAGraph::operator=(NFAGraph&& 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 NFAGraph::AddNewVertex() {
|
||||||
|
vertexes_.emplace(count_vertexes_, this);
|
||||||
|
GetVertex(count_vertexes_).number_ = count_vertexes_;
|
||||||
|
return count_vertexes_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFAGraph::AddFinalVertex(size_t number) {
|
||||||
|
if (!GetVertex(number).is_final_) {
|
||||||
|
GetVertex(number).is_final_ = true;
|
||||||
|
final_vertexes_.push_back(number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFAGraph::AddStartVertex(size_t number) {
|
||||||
|
if (!GetVertex(number).is_start_) {
|
||||||
|
GetVertex(number).is_start_ = true;
|
||||||
|
start_vertexes_.push_back(number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFAGraph::RemoveVertex(size_t number) {
|
||||||
|
RemoveFinalVertex(number);
|
||||||
|
RemoveStartVertex(number);
|
||||||
|
vertexes_.erase(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFAGraph::RemoveFinalVertex(size_t number) {
|
||||||
|
for (size_t i = 0; i < final_vertexes_.size(); ++i) {
|
||||||
|
if (final_vertexes_[i] == number) {
|
||||||
|
GetVertex(number).is_final_ = false;
|
||||||
|
std::swap(final_vertexes_[i], final_vertexes_.back());
|
||||||
|
final_vertexes_.pop_back();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFAGraph::RemoveStartVertex(size_t number) {
|
||||||
|
for (size_t i = 0; i < start_vertexes_.size(); ++i) {
|
||||||
|
if (start_vertexes_[i] == number) {
|
||||||
|
GetVertex(number).is_start_ = false;
|
||||||
|
std::swap(start_vertexes_[i], start_vertexes_.back());
|
||||||
|
start_vertexes_.pop_back();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFAGraph::Composition(NFAGraph&& nfa_graph,
|
||||||
|
std::vector<size_t> start_vertexes,
|
||||||
|
std::vector<size_t> final_vertexes) {
|
||||||
|
auto add_final_vertexes = nfa_graph.final_vertexes_;
|
||||||
|
auto add_start_vertexes = nfa_graph.start_vertexes_;
|
||||||
|
|
||||||
|
size_t new_count_vertexes = count_vertexes_;
|
||||||
|
|
||||||
|
for (auto& i: nfa_graph.vertexes_) {
|
||||||
|
new_count_vertexes = std::max(new_count_vertexes, i.first + count_vertexes_ + 1);
|
||||||
|
i.second.number_ += count_vertexes_;
|
||||||
|
std::map<char, std::set<size_t>> new_transitions;
|
||||||
|
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_.emplace(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) {
|
||||||
|
GetVertex(i).transitions_[' '].insert(j);
|
||||||
|
GetVertex(j).back_transitions_[' '].insert(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& i: add_final_vertexes) {
|
||||||
|
for (auto& j: final_vertexes) {
|
||||||
|
GetVertex(i).transitions_[' '].insert(j);
|
||||||
|
GetVertex(j).back_transitions_[' '].insert(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& i: add_final_vertexes) {
|
||||||
|
GetVertex(i).is_final_ = false;
|
||||||
|
}
|
||||||
|
for (auto& i: add_start_vertexes) {
|
||||||
|
GetVertex(i).is_start_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NFAGraph::Vertex& NFAGraph::GetVertex(size_t number) {
|
||||||
|
if (!NotExistVertex(number))
|
||||||
|
return vertexes_.at(number);
|
||||||
|
throw std::out_of_range("This vertex don't exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NFAGraph::NotExistVertex(size_t number) {
|
||||||
|
return !vertexes_.count(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NFAGraph::GetCountVertexes() const {
|
||||||
|
return count_vertexes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NFAGraph::GetReallyCountVertexes() const {
|
||||||
|
return vertexes_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<size_t>& NFAGraph::GetFinalVertexes() const {
|
||||||
|
return final_vertexes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<size_t>& NFAGraph::GetStartVertexes() const {
|
||||||
|
return start_vertexes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFAGraph::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_) {
|
||||||
|
for (auto k: j.second) {
|
||||||
|
std::cout << i.second.number_ << "." << k << " <" << j.first << ">" <<
|
||||||
|
std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFAGraph::CreateDotFile(const std::string& filename) const {
|
||||||
|
std::ofstream out(filename);
|
||||||
|
out << "digraph G {\n";
|
||||||
|
|
||||||
|
for (auto& i: vertexes_) {
|
||||||
|
for (auto& j: i.second.transitions_) {
|
||||||
|
for (auto& k: j.second) {
|
||||||
|
if (j.first == ' ')
|
||||||
|
out << i.first << "->" << k << "[label=" << "EPS" << "]\n";
|
||||||
|
else
|
||||||
|
out << i.first << "->" << k << "[label=" << j.first << "]\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i.second.IsStart() && i.second.IsFinal()) {
|
||||||
|
out << " " << i.first << " [shape=star];\n";
|
||||||
|
} else if (i.second.IsStart()) {
|
||||||
|
out << " " << i.first << " [shape=rarrow];\n";
|
||||||
|
} else if (i.second.IsFinal()) {
|
||||||
|
out << " " << i.first << " [shape=Msquare];\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out << "}\n";
|
||||||
|
}
|
||||||
|
}
|
61
src/NFA/NFAGraphVertex.cpp
Normal file
61
src/NFA/NFAGraphVertex.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#include "NFA/NFAGraph.hpp"
|
||||||
|
|
||||||
|
using Vertex = NFA::NFAGraph::Vertex;
|
||||||
|
|
||||||
|
Vertex::Vertex(NFAGraph* 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, 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].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(NFAGraph* 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_);
|
||||||
|
}
|
||||||
|
}
|
46
src/converters/DFAToFDFA.cpp
Normal file
46
src/converters/DFAToFDFA.cpp
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#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.NotExistVertex(i)) continue;
|
||||||
|
number_vertex_in_DFA[i] = result.AddNewVertex();
|
||||||
|
}
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
if (graph.NotExistVertex(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, number_vertex_in_DFA[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;
|
||||||
|
}
|
||||||
|
}
|
109
src/converters/DFAToMinDFA.cpp
Normal file
109
src/converters/DFAToMinDFA.cpp
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
#include "converters/DFAToMinDFA.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
DFAGraph DFAGraphToMinDFAGraph(DFAGraph&& graph) {
|
||||||
|
const int n = graph.GetCountVertexes();
|
||||||
|
DFAGraph result;
|
||||||
|
|
||||||
|
std::vector<char> alphabet;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::set<char> set_alphabet;
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
if (graph.NotExistVertex(i)) continue;
|
||||||
|
for (auto i: graph.GetVertex(i).GetTransitions()) {
|
||||||
|
set_alphabet.insert(i.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alphabet = std::vector<char>(set_alphabet.begin(), set_alphabet.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;
|
||||||
|
}
|
||||||
|
}
|
167
src/converters/DFAToRegular.cpp
Normal file
167
src/converters/DFAToRegular.cpp
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
#include "converters/DFAToRegular.hpp"
|
||||||
|
#include "regular/RegularTree.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
std::string DFAGraphToRegular(DFAGraph&& graph) {
|
||||||
|
const size_t n = graph.GetCountVertexes() + 1;
|
||||||
|
|
||||||
|
std::map<size_t, size_t> rename;
|
||||||
|
size_t start = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < n - 1; ++i) {
|
||||||
|
if (graph.NotExistVertex(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++;
|
||||||
|
}
|
||||||
|
std::vector<std::vector<std::set<std::string>>> transitions(cnt,
|
||||||
|
std::vector<std::set<std::string>>(cnt));
|
||||||
|
|
||||||
|
for (int i = 0; i < n - 1; ++i) {
|
||||||
|
if (graph.NotExistVertex(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("( )");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const bool print_table = true;
|
||||||
|
auto PrintTable = [cnt, &transitions](int i) {
|
||||||
|
std::ofstream out("ConvertToRegular/" + std::to_string(cnt - i) + ".dot");
|
||||||
|
out << "digraph G {\n";
|
||||||
|
|
||||||
|
for (int j = 0; j < i; ++j) {
|
||||||
|
for (int k = 0; k < i; ++k) {
|
||||||
|
std::string j_to_k = "";
|
||||||
|
for (const std::string& s: transitions[j][k]) {
|
||||||
|
j_to_k += "(";
|
||||||
|
j_to_k += s;
|
||||||
|
j_to_k += ")";
|
||||||
|
j_to_k += "|";
|
||||||
|
}
|
||||||
|
if (j_to_k.size())
|
||||||
|
j_to_k.pop_back();
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
out << j << "->" << k << "[label=\"" << regular::RegularTree(j_to_k).ToString() << "\"]\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << " " << 1 << " [shape=rarrow];\n";
|
||||||
|
out << " " << 0 << " [shape=Msquare];\n";
|
||||||
|
out << "}\n";
|
||||||
|
};
|
||||||
|
if (print_table) {
|
||||||
|
PrintTable(cnt);
|
||||||
|
}
|
||||||
|
for (int i = cnt - 1; i > 1; --i) {
|
||||||
|
std::vector<std::vector<std::set<std::string>>> new_transitions(cnt,
|
||||||
|
std::vector<std::set<std::string>>(cnt));
|
||||||
|
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();
|
||||||
|
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();
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
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();
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
i_to_k = "(" + i_to_k + ")";
|
||||||
|
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (print_table) {
|
||||||
|
PrintTable(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string loop;
|
||||||
|
std::string start_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 + ")*";
|
||||||
|
} else {
|
||||||
|
loop = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const std::string& s: transitions[1][0]) {
|
||||||
|
start_to_end += "(";
|
||||||
|
start_to_end += s;
|
||||||
|
start_to_end += ")";
|
||||||
|
start_to_end += "|";
|
||||||
|
}
|
||||||
|
if (start_to_end.size())
|
||||||
|
start_to_end.pop_back();
|
||||||
|
transitions[0][0].clear();
|
||||||
|
transitions[1][0].clear();
|
||||||
|
transitions[1][0].insert(loop + "(" + start_to_end + ")");
|
||||||
|
|
||||||
|
return loop + "(" + start_to_end + ")";
|
||||||
|
}
|
||||||
|
}
|
12
src/converters/InvertFDFA.cpp
Normal file
12
src/converters/InvertFDFA.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "converters/InvertFDFA.hpp"
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
DFAGraph InvertFDFAGraph(DFAGraph&& fdfa_graph) {
|
||||||
|
const size_t n = fdfa_graph.GetCountVertexes();
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
if (fdfa_graph.NotExistVertex(i)) continue;
|
||||||
|
fdfa_graph.GetVertex(i).SetFinal(!fdfa_graph.GetVertex(i).IsFinal());
|
||||||
|
}
|
||||||
|
return std::move(fdfa_graph);
|
||||||
|
}
|
||||||
|
}
|
229
src/converters/NFAToDFA.cpp
Normal file
229
src/converters/NFAToDFA.cpp
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
#include "converters/NFAToDFA.hpp"
|
||||||
|
#include <functional>
|
||||||
|
#include <queue>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
NFAGraph AddAllEpsilonTransitions(NFAGraph&& nfa_graph) {
|
||||||
|
const int n = nfa_graph.GetCountVertexes();
|
||||||
|
std::vector<bool> used(n, false);
|
||||||
|
|
||||||
|
std::function<void(int, int)> dfs = [&nfa_graph, &used, &dfs](int u, int v) -> void {
|
||||||
|
used[v] = true;
|
||||||
|
const auto& transitions = nfa_graph.GetVertex(v).GetTransitions();
|
||||||
|
if (transitions.count(' ')) {
|
||||||
|
const auto& s = transitions.at(' ');
|
||||||
|
for (auto i: s) {
|
||||||
|
if (!used[i]) {
|
||||||
|
if (u != i)
|
||||||
|
nfa_graph.GetVertex(u).AddEdge(' ', i);
|
||||||
|
dfs(u, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
if (nfa_graph.NotExistVertex(i)) continue;
|
||||||
|
|
||||||
|
used.assign(n, false);
|
||||||
|
dfs(i, i);
|
||||||
|
}
|
||||||
|
return std::move(nfa_graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
NFAGraph AddAllPossibleFinalVertexes(NFAGraph&& nfa_graph) {
|
||||||
|
if (nfa_graph.GetStartVertexes().size() != 1) {
|
||||||
|
size_t start_vertex = nfa_graph.AddNewVertex();
|
||||||
|
for (auto v: nfa_graph.GetStartVertexes()) {
|
||||||
|
nfa_graph.GetVertex(start_vertex).AddEdge(' ', v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto& v: nfa_graph.GetFinalVertexes()) {
|
||||||
|
const auto& transitions = nfa_graph.GetVertex(v).GetBackTransitions();
|
||||||
|
if (transitions.count(' ')) {
|
||||||
|
const auto& s = transitions.at(' ');
|
||||||
|
for (auto i: s) {
|
||||||
|
nfa_graph.GetVertex(i).SetFinal(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::move(nfa_graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
NFAGraph DeleteEpsilonTransitions(NFAGraph&& nfa_graph) {
|
||||||
|
const int n = nfa_graph.GetCountVertexes();
|
||||||
|
|
||||||
|
for (int v = 0; v < n; ++v) {
|
||||||
|
if (nfa_graph.NotExistVertex(v)) continue;
|
||||||
|
|
||||||
|
const auto& transitions = nfa_graph.GetVertex(v).GetTransitions();
|
||||||
|
if (transitions.count(' ')) {
|
||||||
|
auto s = transitions.at(' ');
|
||||||
|
for (auto u: s) {
|
||||||
|
for (auto& i: nfa_graph.GetVertex(u).GetTransitions()) {
|
||||||
|
if (i.first == ' ') continue;
|
||||||
|
for (auto t: i.second) {
|
||||||
|
nfa_graph.GetVertex(v).AddEdge(i.first, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto u: s) {
|
||||||
|
nfa_graph.GetVertex(v).RemoveEdge(' ', u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::move(nfa_graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
NFAGraph DeleteTransitionsByOneLetter(NFAGraph&& nfa_graph) {
|
||||||
|
const int n = nfa_graph.GetCountVertexes();
|
||||||
|
|
||||||
|
NFAGraph 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 (nfa_graph.NotExistVertex(i)) continue;
|
||||||
|
for (const auto& j: nfa_graph.GetVertex(i).GetTransitions()) {
|
||||||
|
if (j.second.size() > 0)
|
||||||
|
alphabet.insert(j.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto i: nfa_graph.GetStartVertexes()) {
|
||||||
|
queue.push({i});
|
||||||
|
number_vertex_in_result_tree[{i}] = result_tree.AddNewVertex();
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool print_table = true;
|
||||||
|
const size_t length_set = 10;
|
||||||
|
if (print_table) {
|
||||||
|
std::cout << std::setw(length_set) << "vertex" << " | ";
|
||||||
|
for (auto i: alphabet) {
|
||||||
|
std::cout << std::string(length_set / 2, ' ') << i << std::string(length_set - length_set / 2 - 1, ' ') << " | ";
|
||||||
|
}
|
||||||
|
std::cout << std::setw(length_set) << "new number" << " | ";
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << std::string((length_set + 3) * (alphabet.size() + 2) - 1, '-') << std::endl;
|
||||||
|
}
|
||||||
|
while (!queue.empty()) {
|
||||||
|
auto current = queue.front();
|
||||||
|
queue.pop();
|
||||||
|
|
||||||
|
if (print_table) {
|
||||||
|
std::string res;
|
||||||
|
for (int v: current) {
|
||||||
|
res += std::to_string(v) + ",";
|
||||||
|
}
|
||||||
|
if (res.length())
|
||||||
|
res.pop_back();
|
||||||
|
std::cout << std::setw(length_set) << res << " | ";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto symbol: alphabet) {
|
||||||
|
std::set<size_t> result;
|
||||||
|
for (auto v: current) {
|
||||||
|
const auto& transitions = nfa_graph.GetVertex(v).GetTransitions();
|
||||||
|
if (transitions.count(symbol)) {
|
||||||
|
const auto& s = transitions.at(symbol);
|
||||||
|
result.insert(s.begin(), s.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (print_table) {
|
||||||
|
std::string res;
|
||||||
|
if (result.size() == 0) {
|
||||||
|
std::cout << std::setw(length_set) << '-' << " | ";
|
||||||
|
} else {
|
||||||
|
for (int v: result) {
|
||||||
|
res += std::to_string(v) + ",";
|
||||||
|
}
|
||||||
|
if (res.length())
|
||||||
|
res.pop_back();
|
||||||
|
std::cout << std::setw(length_set) << res << " | ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (print_table) {
|
||||||
|
std::cout << std::setw(length_set) << number_vertex_in_result_tree[current] << "|";
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (nfa_graph.GetVertex(i).IsFinal())
|
||||||
|
result_tree.GetVertex(v).SetFinal(true);
|
||||||
|
if (nfa_graph.GetVertex(i).IsStart())
|
||||||
|
result_tree.GetVertex(v).SetStart(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return result_tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
DFAGraph NFAGraphToDFAGraph(NFAGraph&& nfa_graph) {
|
||||||
|
nfa_graph = AddAllEpsilonTransitions(std::move(nfa_graph));
|
||||||
|
nfa_graph = AddAllPossibleFinalVertexes(std::move(nfa_graph));
|
||||||
|
nfa_graph = DeleteEpsilonTransitions(std::move(nfa_graph));
|
||||||
|
nfa_graph.CreateDotFile("5.dot");
|
||||||
|
nfa_graph = DeleteTransitionsByOneLetter(std::move(nfa_graph));
|
||||||
|
nfa_graph.CreateDotFile("6.dot");
|
||||||
|
|
||||||
|
const int n = nfa_graph.GetCountVertexes();
|
||||||
|
DFAGraph result;
|
||||||
|
std::map<int, int> number_vertex_in_DFA;
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
if (nfa_graph.NotExistVertex(i)) continue;
|
||||||
|
number_vertex_in_DFA[i] = result.AddNewVertex();
|
||||||
|
}
|
||||||
|
bool exists_start_vertex = false;
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
if (nfa_graph.NotExistVertex(i)) continue;
|
||||||
|
if (nfa_graph.GetVertex(i).IsFinal())
|
||||||
|
result.GetVertex(number_vertex_in_DFA[i]).SetFinal(true);
|
||||||
|
if (nfa_graph.GetVertex(i).IsStart()) {
|
||||||
|
if (exists_start_vertex) {
|
||||||
|
throw std::runtime_error("I can't delete starts vertex");
|
||||||
|
}
|
||||||
|
result.GetVertex(number_vertex_in_DFA[i]).SetStart(true);
|
||||||
|
exists_start_vertex = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& transitions = nfa_graph.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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!exists_start_vertex) {
|
||||||
|
throw std::runtime_error("I can't find start vertex");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
97
src/converters/RegularToNFA.cpp
Normal file
97
src/converters/RegularToNFA.cpp
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
#include "converters/RegularToNFA.hpp"
|
||||||
|
#include "regular/RegularTree.hpp"
|
||||||
|
#include "NFA/NFAGraph.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>
|
||||||
|
NFAGraph RegularToNFA(std::unique_ptr<Node, deleter> node) {
|
||||||
|
NFAGraph result;
|
||||||
|
if (node->type == Node::Type::Word) {
|
||||||
|
auto end = result.AddNewVertex();
|
||||||
|
auto start = end;
|
||||||
|
result.AddStartVertex(end);
|
||||||
|
for (char i: node->word) {
|
||||||
|
auto tmp = result.AddNewVertex();
|
||||||
|
result.GetVertex(end).AddEdge(i, tmp);
|
||||||
|
end = tmp;
|
||||||
|
}
|
||||||
|
if (node->modifier == Node::Modifier::Plus) {
|
||||||
|
result.GetVertex(end).AddEdge(' ', start);
|
||||||
|
} else if (node->modifier == Node::Modifier::Star) {
|
||||||
|
result.GetVertex(end).AddEdge(' ', start);
|
||||||
|
result.GetVertex(start).AddEdge(' ', end);
|
||||||
|
}
|
||||||
|
result.AddFinalVertex(end);
|
||||||
|
} else if (node->type == Node::Type::Concatenation) {
|
||||||
|
result = RegularToNFA(std::move(node->children[0]));
|
||||||
|
for (auto it = node->children.begin() + 1; it != node->children.end(); ++it) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
const auto& start_vertexes = result.GetStartVertexes();
|
||||||
|
const auto& end_vertexes = result.GetFinalVertexes();
|
||||||
|
|
||||||
|
size_t start = result.AddNewVertex();
|
||||||
|
for (auto to: start_vertexes) {
|
||||||
|
result.GetVertex(start).AddEdge(' ', to);
|
||||||
|
}
|
||||||
|
auto t = result.GetStartVertexes();
|
||||||
|
for (auto to: t) {
|
||||||
|
result.RemoveStartVertex(to);
|
||||||
|
}
|
||||||
|
result.AddStartVertex(start);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace converters {
|
||||||
|
NFAGraph RegularToNFAGraph(RegularTree&& tree) {
|
||||||
|
const Node& root = tree.GetNode();
|
||||||
|
return RegularToNFA(std::unique_ptr<Node,
|
||||||
|
do_nothing_deleter>(&const_cast<Node&>(tree.GetNode())));
|
||||||
|
}
|
||||||
|
}
|
92
src/main.cpp
92
src/main.cpp
|
@ -1,5 +1,95 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "regular/RegularTree.hpp"
|
||||||
|
#include "NFA/NFAGraph.hpp"
|
||||||
|
#include "DFA/DFAGraph.hpp"
|
||||||
|
#include "converters/RegularToNFA.hpp"
|
||||||
|
#include "converters/NFAToDFA.hpp"
|
||||||
|
#include "converters/DFAToFDFA.hpp"
|
||||||
|
#include "converters/DFAToMinDFA.hpp"
|
||||||
|
#include "converters/DFAToRegular.hpp"
|
||||||
|
#include "converters/InvertFDFA.hpp"
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
#define RegularStringToDFAGraph(s) NFAGraphToDFAGraph(RegularToNFAGraph(RegularTree(s)))
|
||||||
|
#define RegularStringToMinDFAGraph(s) DFAGraphToMinDFAGraph(NFAGraphToDFAGraph(RegularToNFAGraph(RegularTree(s))))
|
||||||
|
#define InvertRegularString(v, s) RegularTree(DFAGraphToRegular(DFAGraphToMinDFAGraph(InvertFDFAGraph(DFAGraphToMinDFAGraph(DFAGraphToFDFAGraph(NFAGraphToDFAGraph(RegularToNFAGraph(RegularTree(s))), v)))))).ToString()
|
||||||
|
|
||||||
|
using namespace regular;
|
||||||
|
using namespace NFA;
|
||||||
|
using namespace DFA;
|
||||||
|
using namespace converters;
|
||||||
|
|
||||||
|
void example1() {
|
||||||
|
RegularTree r("a*");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r)); // Regular to FA
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); // to DFA
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); // minimize
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph)); // DFA to regular
|
||||||
|
r = RegularTree(reg); // create regular
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r)); // to FA
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree)); // to DFA
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph)); // minimize
|
||||||
|
DFA_graph.Print(); // print
|
||||||
|
}
|
||||||
|
|
||||||
|
void example2() {
|
||||||
|
NFAGraph nfa_graph;
|
||||||
|
const size_t N = 10;
|
||||||
|
|
||||||
|
size_t a[N];
|
||||||
|
for (size_t i = 0; i < N; ++i)
|
||||||
|
a[i] = nfa_graph.AddNewVertex();
|
||||||
|
|
||||||
|
auto AddEdge = [&nfa_graph, &a](char symbol, int u, int v) {
|
||||||
|
nfa_graph.GetVertex(a[u]).AddEdge(symbol, a[v]);
|
||||||
|
};
|
||||||
|
|
||||||
|
AddEdge('a', 0, 1);
|
||||||
|
AddEdge('b', 0, 2);
|
||||||
|
AddEdge('b', 1, 3);
|
||||||
|
AddEdge('b', 2, 4);
|
||||||
|
|
||||||
|
DFAGraph dfa_graph = NFAGraphToDFAGraph(std::move(nfa_graph));
|
||||||
|
dfa_graph = DFAGraphToMinDFAGraph(std::move(dfa_graph));
|
||||||
|
dfa_graph.Print();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
std::map<size_t, std::string> names;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
std::cout << "hello world";
|
NFAGraph nfa;
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
nfa.AddNewVertex();
|
||||||
|
auto AddEdge = [&](char symbol, int u, int v) {
|
||||||
|
nfa.GetVertex(u).AddEdge(symbol, v);
|
||||||
|
};
|
||||||
|
|
||||||
|
AddEdge('a', 1, 1);
|
||||||
|
AddEdge('a', 1, 2);
|
||||||
|
AddEdge('b', 2, 1);
|
||||||
|
AddEdge('b', 1, 3);
|
||||||
|
AddEdge('a', 3, 1);
|
||||||
|
AddEdge('b', 3, 4);
|
||||||
|
AddEdge('a', 4, 3);
|
||||||
|
AddEdge('a', 0, 1);
|
||||||
|
nfa.GetVertex(0).SetStart(true);
|
||||||
|
nfa.GetVertex(1).SetFinal(true);
|
||||||
|
|
||||||
|
nfa.CreateDotFile("3.dot");
|
||||||
|
DFAGraph dfa = NFAGraphToDFAGraph(std::move(nfa));
|
||||||
|
dfa = DFAGraphToFDFAGraph(std::move(dfa), {'a', 'b'});
|
||||||
|
dfa = InvertFDFAGraph(std::move(dfa));
|
||||||
|
dfa.CreateDotFile("1.dot");
|
||||||
|
dfa.CreateDotFile("8.dot");
|
||||||
|
dfa = DFAGraphToMinDFAGraph(std::move(dfa));
|
||||||
|
dfa.CreateDotFile("2.dot");
|
||||||
}
|
}
|
||||||
|
|
19
src/regular/RegularTree.cpp
Normal file
19
src/regular/RegularTree.cpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#include "regular/RegularTree.hpp"
|
||||||
|
|
||||||
|
namespace regular {
|
||||||
|
RegularTree::RegularTree(const std::string& regular) {
|
||||||
|
node_.Parse(regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
const RegularTree::Node& RegularTree::GetNode() const {
|
||||||
|
return node_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegularTree::Print() const {
|
||||||
|
node_.Print();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RegularTree::ToString() const {
|
||||||
|
return node_.ToString();
|
||||||
|
}
|
||||||
|
}
|
254
src/regular/RegularTreeNode.cpp
Normal file
254
src/regular/RegularTreeNode.cpp
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
#include "regular/RegularTree.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using Node = regular::RegularTree::Node;
|
||||||
|
Node::Node() {}
|
||||||
|
Node::Node(Type type) : type(type) {}
|
||||||
|
|
||||||
|
void Node::Parse(const std::string& regular) {
|
||||||
|
type = Type::Addition;
|
||||||
|
ParseCurrentType(std::string_view(regular.c_str(), regular.size()));
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
Compression();
|
||||||
|
Compression2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::Print() const {
|
||||||
|
Print(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::ParseCurrentType(const std::string_view regular) {
|
||||||
|
const size_t n = regular.size();
|
||||||
|
children.clear();
|
||||||
|
word.clear();
|
||||||
|
|
||||||
|
auto AddChild = [this](const std::string_view regular) {
|
||||||
|
this->children.push_back(std::make_unique<Node>(Type::Addition));
|
||||||
|
this->children.back()->ParseCurrentType(regular);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (n == 1) {
|
||||||
|
type = Type::Word;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == Type::Addition) {
|
||||||
|
int balance = 0;
|
||||||
|
int begin_child = 0;
|
||||||
|
bool wrapped_brackets = (regular[0] == '(');
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
if (regular[i] == '(') {
|
||||||
|
++balance;
|
||||||
|
} else if (regular[i] == ')') {
|
||||||
|
--balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regular[i] == '|') {
|
||||||
|
if (balance == 0) {
|
||||||
|
AddChild(regular.substr(begin_child + wrapped_brackets, i -
|
||||||
|
begin_child - 2 *
|
||||||
|
wrapped_brackets));
|
||||||
|
begin_child = i + 1;
|
||||||
|
|
||||||
|
if (i + 1 < n)
|
||||||
|
wrapped_brackets = (regular[i + 1] == '(');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (i + 1 == n) {
|
||||||
|
if (children.size() == 0) {
|
||||||
|
type = Type::Concatenation;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
AddChild(regular.substr(begin_child + wrapped_brackets, i -
|
||||||
|
begin_child + 1 - 2 *
|
||||||
|
wrapped_brackets));
|
||||||
|
begin_child = i + 1;
|
||||||
|
if (i + 1 < n)
|
||||||
|
wrapped_brackets = (regular[i + 1] == '(');
|
||||||
|
}
|
||||||
|
} else if (balance == 0) {
|
||||||
|
wrapped_brackets = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == Type::Concatenation) {
|
||||||
|
int balance = 0;
|
||||||
|
int begin_child = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
if (regular[i] == '(') {
|
||||||
|
++balance;
|
||||||
|
if (balance == 1) {
|
||||||
|
if (begin_child < i) {
|
||||||
|
AddChild(regular.substr(begin_child, i - begin_child));
|
||||||
|
}
|
||||||
|
begin_child = i + 1;
|
||||||
|
}
|
||||||
|
} else if (regular[i] == ')') {
|
||||||
|
--balance;
|
||||||
|
if (balance == 0) {
|
||||||
|
AddChild(regular.substr(begin_child, i - begin_child));
|
||||||
|
begin_child = i + 1;
|
||||||
|
}
|
||||||
|
} else if (i + 1 == n) {
|
||||||
|
if (balance != 0) {
|
||||||
|
throw std::logic_error("invalid regular");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children.size() == 0) {
|
||||||
|
type = Type::Word;
|
||||||
|
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 {
|
||||||
|
AddChild(regular.substr(begin_child, i - begin_child + 1));
|
||||||
|
begin_child = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (balance == 0) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == Type::Word) {
|
||||||
|
bool exist_modifire = regular.back() == '+' || regular.back() == '*';
|
||||||
|
if (regular.back() == '+') {
|
||||||
|
modifier = Modifier::Plus;
|
||||||
|
} else if (regular.back() == '*') {
|
||||||
|
modifier = Modifier::Star;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < n - exist_modifire; ++i) {
|
||||||
|
if (regular[i] == '|' || regular[i] == '(' || regular[i] == ')') {
|
||||||
|
throw std::logic_error("invalid regular");
|
||||||
|
}
|
||||||
|
word += regular[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::Compression() {
|
||||||
|
for (auto& i: children) {
|
||||||
|
i->Compression();
|
||||||
|
}
|
||||||
|
if (children.size() == 1 && modifier == Modifier::None) {
|
||||||
|
auto tmp = std::move(*children[0]);
|
||||||
|
*this = std::move(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::Compression2() {
|
||||||
|
for (auto& i: children) {
|
||||||
|
i->Compression2();
|
||||||
|
}
|
||||||
|
bool f = type == Type::Concatenation;
|
||||||
|
for (auto& i: children) {
|
||||||
|
f &= i->modifier == Modifier::None;
|
||||||
|
f &= i->type == Type::Word;
|
||||||
|
}
|
||||||
|
if (f) {
|
||||||
|
auto tmp = std::move(*children[0]);
|
||||||
|
tmp.modifier = modifier;
|
||||||
|
for (int i = 1; i < children.size(); ++i) {
|
||||||
|
tmp.word += children[i]->word;
|
||||||
|
}
|
||||||
|
*this = std::move(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::Print(int nesting_level) const {
|
||||||
|
auto PrintNesingLevel = [](int nesting_level) {
|
||||||
|
for (int i = 0; i < nesting_level; ++i) {
|
||||||
|
std::cout << " ";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PrintNesingLevel(nesting_level);
|
||||||
|
if (type == Type::Addition) {
|
||||||
|
std::cout << "Addition";
|
||||||
|
if (modifier == Modifier::Plus) {
|
||||||
|
std::cout << "+";
|
||||||
|
} else if (modifier == Modifier::Star) {
|
||||||
|
std::cout << "*";
|
||||||
|
}
|
||||||
|
std::cout << " " << std::to_string(children.size()) << ":" << std::endl;
|
||||||
|
} else if (type == Type::Concatenation) {
|
||||||
|
std::cout << "Concatenation";
|
||||||
|
if (modifier == Modifier::Plus) {
|
||||||
|
std::cout << "+";
|
||||||
|
} else if (modifier == Modifier::Star) {
|
||||||
|
std::cout << "*";
|
||||||
|
}
|
||||||
|
std::cout << " " << children.size() << ":" << std::endl;
|
||||||
|
} else if (type == Type::Word) {
|
||||||
|
std::cout << "Word";
|
||||||
|
if (modifier == Modifier::Plus) {
|
||||||
|
std::cout << "+";
|
||||||
|
} else if (modifier == Modifier::Star) {
|
||||||
|
std::cout << "*";
|
||||||
|
}
|
||||||
|
std::cout << ": " << word << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& i: children) {
|
||||||
|
i->Print(nesting_level + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string regular::RegularTree::Node::ToString() const {
|
||||||
|
std::string res;
|
||||||
|
if (type == Type::Word) {
|
||||||
|
res = word;
|
||||||
|
if (modifier == Modifier::Plus)
|
||||||
|
res = "(" + res + ")+";
|
||||||
|
else if (modifier == Modifier::Star)
|
||||||
|
res = "(" + res + ")*";
|
||||||
|
} else if (type == Type::Concatenation) {
|
||||||
|
for (auto& i: children) {
|
||||||
|
res += i->ToString();
|
||||||
|
}
|
||||||
|
if (modifier == Modifier::Plus)
|
||||||
|
res = "(" + res + ")+";
|
||||||
|
else if (modifier == Modifier::Star)
|
||||||
|
res = "(" + res + ")*";
|
||||||
|
} else if (type == Type::Addition) {
|
||||||
|
for (auto& i: children) {
|
||||||
|
res += i->ToString();
|
||||||
|
res += "|";
|
||||||
|
}
|
||||||
|
if (res.size())
|
||||||
|
res.pop_back();
|
||||||
|
res = "(" + res + ")";
|
||||||
|
if (modifier == Modifier::Plus)
|
||||||
|
res += "+";
|
||||||
|
else if (modifier == Modifier::Star)
|
||||||
|
res += "*";
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
40
tests/DFAToMinDFA/CountSizesMinDFA.cpp
Normal file
40
tests/DFAToMinDFA/CountSizesMinDFA.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#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;
|
||||||
|
|
||||||
|
size_t GetCountVertexes(const std::string& regular) {
|
||||||
|
RegularTree r(regular);
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
return DFA_graph.GetReallyCountVertexes();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DFA_to_min_DFA, a_start) {
|
||||||
|
EXPECT_EQ(GetCountVertexes("a*"), GetCountVertexes("( a | )*| | | aaa a a"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DFA_to_min_DFA, a_plus) {
|
||||||
|
EXPECT_EQ(GetCountVertexes("a+"), GetCountVertexes("( a | a a )+|a | a |a "));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DFA_to_min_DFA, a_star_or_b_star) {
|
||||||
|
EXPECT_EQ(GetCountVertexes("a*|b*"), GetCountVertexes("a|b|a*|a+|b*|b+|bbb b b b| a a aa a aa | a+"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DFA_to_min_DFA, epsilon) {
|
||||||
|
EXPECT_EQ(GetCountVertexes(" "), GetCountVertexes(" | | | "));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DFA_to_min_DFA, a_or_b_star) {
|
||||||
|
EXPECT_EQ(GetCountVertexes("(a|b)*"), GetCountVertexes("a+|b+|a*|b*|a*b*a*|a|b(a|b)*|b| |(a|b)*"));
|
||||||
|
}
|
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*");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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);
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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);
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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);
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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*)+");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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*)+");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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));
|
||||||
|
}
|
||||||
|
}
|
209
tests/DFAToRegular/DFAToRegular2.cpp
Normal file
209
tests/DFAToRegular/DFAToRegular2.cpp
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
#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_regular2, a_star) {
|
||||||
|
RegularTree r("a*");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
reg = RegularTree(reg).ToString();
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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_regular2, a_plus) {
|
||||||
|
std::string regulars[] = {"a+", "(a)+", "(a+)"};
|
||||||
|
for (const auto& regular: regulars) {
|
||||||
|
RegularTree r(regular);
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
reg = RegularTree(reg).ToString();
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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_regular2, abc) {
|
||||||
|
std::string regulars[] = {"abc"};
|
||||||
|
for (const auto& regular: regulars) {
|
||||||
|
RegularTree r(regular);
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
reg = RegularTree(reg).ToString();
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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_regular2, a_or_b_or_c) {
|
||||||
|
std::string regulars[] = {};
|
||||||
|
for (const auto& regular: regulars) {
|
||||||
|
RegularTree r("a|b|c");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
reg = RegularTree(reg).ToString();
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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_regular2, a_star_or_b_star_or_c_star) {
|
||||||
|
std::string regulars[] = {"a*|b*|c*", "(a*)|(b*|c*)", "(a*|b*|c*)", "((a*)|(b*)|(c*))"};
|
||||||
|
for (const auto& regular: regulars) {
|
||||||
|
RegularTree r(regular);
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
reg = RegularTree(reg).ToString();
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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_regular2, _a_star_or_b_star_or_c_star_plus) {
|
||||||
|
RegularTree r("(a*|b*|c*)+");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
reg = RegularTree(reg).ToString();
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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_regular2, _a_or_b_or_c_star_plus) {
|
||||||
|
RegularTree r("(a|b|c*)+");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string reg = DFAGraphToRegular(std::move(DFA_graph));
|
||||||
|
reg = RegularTree(reg).ToString();
|
||||||
|
|
||||||
|
r = RegularTree(reg);
|
||||||
|
NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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));
|
||||||
|
}
|
||||||
|
}
|
69
tests/GenericTest/GenericTest1.cpp
Normal file
69
tests/GenericTest/GenericTest1.cpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <random>
|
||||||
|
#include "regular/RegularTree.hpp"
|
||||||
|
#include "converters/RegularToNFA.hpp"
|
||||||
|
#include "converters/NFAToDFA.hpp"
|
||||||
|
#include "converters/DFAToMinDFA.hpp"
|
||||||
|
#include "converters/DFAToFDFA.hpp"
|
||||||
|
#include "converters/InvertFDFA.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(generic_tests, divided_5) {
|
||||||
|
DFAGraph DFA_graph;
|
||||||
|
size_t a[10];
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
a[i] = DFA_graph.AddNewVertex();
|
||||||
|
}
|
||||||
|
auto add_edge = [&DFA_graph, &a](size_t in, size_t out, char x) {
|
||||||
|
DFA_graph.GetVertex(a[in]).AddEdge(x, a[out]);
|
||||||
|
};
|
||||||
|
add_edge(5, 6, '0');
|
||||||
|
add_edge(5, 1, '1');
|
||||||
|
add_edge(1, 2, '0');
|
||||||
|
add_edge(1, 3, '1');
|
||||||
|
add_edge(2, 4, '0');
|
||||||
|
add_edge(2, 0, '1');
|
||||||
|
add_edge(3, 1, '0');
|
||||||
|
add_edge(3, 2, '1');
|
||||||
|
add_edge(4, 3, '0');
|
||||||
|
add_edge(4, 4, '1');
|
||||||
|
add_edge(0, 0, '0');
|
||||||
|
add_edge(0, 1, '1');
|
||||||
|
DFA_graph.GetVertex(a[5]).SetStart(true);
|
||||||
|
DFA_graph.GetVertex(a[6]).SetFinal(true);
|
||||||
|
DFA_graph.GetVertex(a[0]).SetFinal(true);
|
||||||
|
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
DFA_graph = NFAGraphToDFAGraph(RegularToNFAGraph(RegularTree(DFAGraphToRegular(std::move(DFA_graph)))));
|
||||||
|
|
||||||
|
auto check = [](const std::string& str) -> bool {
|
||||||
|
bool answer = true;
|
||||||
|
if (str.size() == 1) {
|
||||||
|
return str == "0";
|
||||||
|
}
|
||||||
|
if (str[0] == '0') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int remainder = 0;
|
||||||
|
for (auto i: str) {
|
||||||
|
remainder = remainder * 2 + i - '0';
|
||||||
|
remainder %= 5;
|
||||||
|
}
|
||||||
|
return remainder == 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 2000; ++i) {
|
||||||
|
std::string test = GenerateRandomString({'0', '1'}, rnd() % 1000 + 1);
|
||||||
|
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted(test), check(test));
|
||||||
|
}
|
||||||
|
}
|
111
tests/NFAToDFA/CheckEquivalence.cpp
Normal file
111
tests/NFAToDFA/CheckEquivalence.cpp
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <random>
|
||||||
|
#include "DFA/DFAGraph.hpp"
|
||||||
|
#include "NFA/NFAGraph.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::NFAGraph 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::NFAGraphToDFAGraph(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::NFAGraph 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::NFAGraphToDFAGraph(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));
|
||||||
|
}
|
||||||
|
}
|
181
tests/invertFDFA/InvertFDFA.cpp
Normal file
181
tests/invertFDFA/InvertFDFA.cpp
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <random>
|
||||||
|
#include "regular/RegularTree.hpp"
|
||||||
|
#include "converters/RegularToNFA.hpp"
|
||||||
|
#include "converters/NFAToDFA.hpp"
|
||||||
|
#include "converters/DFAToMinDFA.hpp"
|
||||||
|
#include "converters/DFAToFDFA.hpp"
|
||||||
|
#include "converters/InvertFDFA.hpp"
|
||||||
|
|
||||||
|
using namespace regular;
|
||||||
|
using namespace NFA;
|
||||||
|
using namespace DFA;
|
||||||
|
using namespace converters;
|
||||||
|
|
||||||
|
extern std::mt19937 rnd;
|
||||||
|
|
||||||
|
extern std::string GenerateRandomString(std::vector<char> alphabet, size_t len);
|
||||||
|
|
||||||
|
TEST(invert_DFA, a_star) {
|
||||||
|
RegularTree r("a*");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'});
|
||||||
|
DFA_graph = InvertFDFAGraph(std::move(DFA_graph));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string s = "";
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted(s), false);
|
||||||
|
s += "a";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(invert_DFA, a_plus) {
|
||||||
|
std::string regulars[] = {"a+", "(a)+", "(a+)"};
|
||||||
|
for (const auto& regular: regulars) {
|
||||||
|
RegularTree r(regular);
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'});
|
||||||
|
DFA_graph = InvertFDFAGraph(std::move(DFA_graph));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
std::string s = "";
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted(s), true);
|
||||||
|
s += "a";
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted(s), false);
|
||||||
|
s += "a";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(invert_DFA, abc) {
|
||||||
|
std::string regulars[] = {"abc"};
|
||||||
|
for (const auto& regular: regulars) {
|
||||||
|
RegularTree r(regular);
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'});
|
||||||
|
DFA_graph = InvertFDFAGraph(std::move(DFA_graph));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted("abc"), false);
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
auto s = GenerateRandomString({'a', 'b', 'c', 'd'}, rnd() % 10);
|
||||||
|
if (s == "abc") continue;
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted(s), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(invert_DFA, a_or_b_or_c) {
|
||||||
|
std::string regulars[] = {};
|
||||||
|
for (const auto& regular: regulars) {
|
||||||
|
RegularTree r("a|b|c");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'});
|
||||||
|
DFA_graph = InvertFDFAGraph(std::move(DFA_graph));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted("a"), false);
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted("b"), false);
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted("c"), false);
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
auto s = GenerateRandomString({'a', 'b', 'c', 'd'}, rnd() % 10);
|
||||||
|
if (s == "a") continue;
|
||||||
|
if (s == "b") continue;
|
||||||
|
if (s == "c") continue;
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted(s), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(invert_DFA, a_star_or_b_star_or_c_star) {
|
||||||
|
std::string regulars[] = {"a*|b*|c*", "(a*)|(b*|c*)", "(a*|b*|c*)", "((a*)|(b*)|(c*))"};
|
||||||
|
for (const auto& regular: regulars) {
|
||||||
|
RegularTree r(regular);
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'});
|
||||||
|
DFA_graph = InvertFDFAGraph(std::move(DFA_graph));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
auto check = [](const std::string str) {
|
||||||
|
std::set<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(""), false);
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
auto s = GenerateRandomString({'a', 'b', 'c', 'd'}, rnd() % 10);
|
||||||
|
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted(s), !check(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(invert_DFA, _a_star_or_b_star_or_c_star_plus) {
|
||||||
|
RegularTree r("(a*|b*|c*)+");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'});
|
||||||
|
DFA_graph = InvertFDFAGraph(std::move(DFA_graph));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
auto check = [](const std::string str) {
|
||||||
|
std::set<char> s(str.begin(), str.end());
|
||||||
|
return s.find('d') == s.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted(""), false);
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
auto s = GenerateRandomString({'a', 'b', 'c', 'd'}, rnd() % 10);
|
||||||
|
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted(s), !check(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(invert_DFA, _a_or_b_or_c_star_plus) {
|
||||||
|
RegularTree r("(a|b|c*)+");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b', 'c', 'd'});
|
||||||
|
DFA_graph = InvertFDFAGraph(std::move(DFA_graph));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
||||||
|
|
||||||
|
auto check = [](const std::string str) {
|
||||||
|
std::set<char> s(str.begin(), str.end());
|
||||||
|
return s.find('d') == s.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted(""), false);
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
auto s = GenerateRandomString({'a', 'b', 'c', 'd'}, rnd() % 10);
|
||||||
|
|
||||||
|
ASSERT_EQ(DFA_graph.Accepted(s), !check(s));
|
||||||
|
}
|
||||||
|
}
|
40
tests/regular/ParseRegular.cpp
Normal file
40
tests/regular/ParseRegular.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "regular/RegularTree.hpp"
|
||||||
|
|
||||||
|
using namespace regular;
|
||||||
|
|
||||||
|
TEST(parse_regular, only_addition) {
|
||||||
|
RegularTree("a");
|
||||||
|
RegularTree("aa");
|
||||||
|
RegularTree("aaa");
|
||||||
|
RegularTree("aaaa");
|
||||||
|
RegularTree("aaaaa");
|
||||||
|
RegularTree("a|aaaa");
|
||||||
|
RegularTree("a|a|a|a|a");
|
||||||
|
RegularTree("hello|world");
|
||||||
|
RegularTree("qe|wr|lkj|alk");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(parse_regular, only_folding) {
|
||||||
|
RegularTree("(kajfkasf(aksdjf)jka(((aksjdf)K)))jakd");
|
||||||
|
RegularTree("(kajsdfk(aksdjf)kajsdf)kjasdkfja(skdjf(((aksjdkadf)ksjf(kdja))))");
|
||||||
|
RegularTree("((((kdjf))))");
|
||||||
|
RegularTree("kasjf(akjsfkjasdg)kajsdg");
|
||||||
|
RegularTree("akjsdf(akjdf(kdjfak(jkasdf)))");
|
||||||
|
RegularTree("123k4j1k351kk21jkj21k6j2k36j1(((((ajkfajsdfkafdalkdjflk)))))");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(parse_regular, only_modifiers) {
|
||||||
|
RegularTree("jlakjdf*aksdjflaf8*laksfj*lakjsf*alksjdf");
|
||||||
|
RegularTree("jlakjdf*aksdjflaf8+laksfj*lakjsf*alksjdf*");
|
||||||
|
RegularTree("jlakjdf*aksdjflaf8*laksfj*lakjsf+alksjdf");
|
||||||
|
RegularTree("jlakjd+aksdjflaf8*laksfj*lakjsf*alksjdf+");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(parse_regular, all_operations) {
|
||||||
|
RegularTree("(alkjdfaksdf*|lkasdj*|(kasjdf|kajdf*|kjd)*|laksjf*)+");
|
||||||
|
RegularTree("(alkjdfaksdf|lkasdj*|(kas+jdf|kajdf*|kjd)*|laksjf*)+");
|
||||||
|
RegularTree("a|(a|(a|(a|)*))*");
|
||||||
|
RegularTree("kj*|kjadf*|(kajsdf|(kajsd|kjadf|(kasjdf)|kajs)*)*");
|
||||||
|
}
|
||||||
|
|
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*");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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);
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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);
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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);
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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*)+");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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*)+");
|
||||||
|
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
||||||
|
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
||||||
|
DFA_graph = DFAGraphToMinDFAGraph(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