fix some bugs and add big test
This commit is contained in:
parent
04109bd54b
commit
34560d3628
|
@ -11,7 +11,6 @@ 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)
|
||||||
|
@ -39,6 +38,7 @@ set(TEST_FILES
|
||||||
tests/invertFDFA/InvertFDFA.cpp
|
tests/invertFDFA/InvertFDFA.cpp
|
||||||
tests/DFAToRegular/DFAToRegular2.cpp
|
tests/DFAToRegular/DFAToRegular2.cpp
|
||||||
tests/DFAToMinDFA/CountSizesMinDFA.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})
|
||||||
|
|
|
@ -30,7 +30,9 @@ std::string reg = DFAGraphToRegular(std::move(DFA_graph)); // В регуляр
|
||||||
RegularTree(reg).ToString() // Получится более красивая регулярка
|
RegularTree(reg).ToString() // Получится более красивая регулярка
|
||||||
```
|
```
|
||||||
Про сами регулярки + * - это плюс и звезда Клини. Их можно писать после слов, или после скобок.
|
Про сами регулярки + * - это плюс и звезда Клини. Их можно писать после слов, или после скобок.
|
||||||
abacaba* ~ (abacaba)\*. a(b)a\* ~ a(b)(a)\*. Для сложения языков используется |. Символом пустого слова является пробел.
|
abacaba\* ~ (abacaba)\*. a(b)a\* ~ a(b)(a)\*. Для сложения языков используется |. Символом пустого слова является пробел.
|
||||||
|
|
||||||
|
Очень важное отличие, что у меня + \* привязываются не к букве, а к слову(например aba* это (aba)\*, а не ab(a)\* как вы ожидаете), это значительное отличие от существующих регулярок, но .ToString у RegularTree всегда + \* выдаст строку у которой перед + \* будет стоять скобочка
|
||||||
|
|
||||||
Примеры регулярок
|
Примеры регулярок
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,7 @@ DFAGraph::DFAGraph(DFAGraph&& another) {
|
||||||
std::swap(count_vertexes_, another.count_vertexes_);
|
std::swap(count_vertexes_, another.count_vertexes_);
|
||||||
std::swap(vertexes_, another.vertexes_);
|
std::swap(vertexes_, another.vertexes_);
|
||||||
std::swap(final_vertexes_, another.final_vertexes_);
|
std::swap(final_vertexes_, another.final_vertexes_);
|
||||||
// TODO
|
std::swap(start_vertex_, another.start_vertex_);
|
||||||
// std::swap(start_vertexes_, another.start_vertexes_);
|
|
||||||
|
|
||||||
for (auto& i: vertexes_)
|
for (auto& i: vertexes_)
|
||||||
i.second.owner_ = this;
|
i.second.owner_ = this;
|
||||||
|
@ -21,8 +20,7 @@ DFAGraph& DFAGraph::operator=(DFAGraph&& another) {
|
||||||
std::swap(count_vertexes_, another.count_vertexes_);
|
std::swap(count_vertexes_, another.count_vertexes_);
|
||||||
std::swap(vertexes_, another.vertexes_);
|
std::swap(vertexes_, another.vertexes_);
|
||||||
std::swap(final_vertexes_, another.final_vertexes_);
|
std::swap(final_vertexes_, another.final_vertexes_);
|
||||||
// TODO
|
std::swap(start_vertex_, another.start_vertex_);
|
||||||
// std::swap(start_vertexes_, another.start_vertexes_);
|
|
||||||
|
|
||||||
for (auto& i: vertexes_)
|
for (auto& i: vertexes_)
|
||||||
i.second.owner_ = this;
|
i.second.owner_ = this;
|
||||||
|
@ -71,6 +69,7 @@ void DFAGraph::RemoveFinalVertex(size_t number) {
|
||||||
void DFAGraph::RemoveStartVertex(size_t number) {
|
void DFAGraph::RemoveStartVertex(size_t number) {
|
||||||
if (start_vertex_ == number) {
|
if (start_vertex_ == number) {
|
||||||
start_vertex_ = -1;
|
start_vertex_ = -1;
|
||||||
|
GetVertex(number).is_start_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -185,7 +185,10 @@ void NFAGraph::CreateDotFile(const std::string& filename) const {
|
||||||
for (auto& i: vertexes_) {
|
for (auto& i: vertexes_) {
|
||||||
for (auto& j: i.second.transitions_) {
|
for (auto& j: i.second.transitions_) {
|
||||||
for (auto& k: j.second) {
|
for (auto& k: j.second) {
|
||||||
out << i.first << "." << k << "[label=" << j.first << "]\n";
|
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()) {
|
if (i.second.IsStart() && i.second.IsFinal()) {
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
#include "converters/DFAToRegular.hpp"
|
#include "converters/DFAToRegular.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace converters {
|
namespace converters {
|
||||||
std::string DFAGraphToRegular(DFAGraph&& graph) {
|
std::string DFAGraphToRegular(DFAGraph&& graph) {
|
||||||
const size_t n = graph.GetCountVertexes() + 1;
|
const size_t n = graph.GetCountVertexes() + 1;
|
||||||
std::string result = "";
|
|
||||||
|
|
||||||
std::vector<std::vector<std::set<std::string>>> transitions(n,
|
|
||||||
std::vector<std::set<std::string>>(n));
|
|
||||||
|
|
||||||
std::map<size_t, size_t> rename;
|
std::map<size_t, size_t> rename;
|
||||||
size_t start = -1;
|
size_t start = -1;
|
||||||
|
|
||||||
for (int i = 0; i < n - 1; ++i) {
|
for (int i = 0; i < n - 1; ++i) {
|
||||||
if (graph.NotExistVertex(i)) continue;
|
if (graph.NotExistVertex(i)) continue;
|
||||||
if (graph.GetVertex(i).IsStart()) start = i;
|
if (graph.GetVertex(i).IsStart()) {
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rename[start] = 1;
|
rename[start] = 1;
|
||||||
|
@ -23,7 +22,8 @@ std::string DFAGraphToRegular(DFAGraph&& graph) {
|
||||||
if (i == start) continue;
|
if (i == start) continue;
|
||||||
rename[i] = cnt++;
|
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) {
|
for (int i = 0; i < n - 1; ++i) {
|
||||||
if (graph.NotExistVertex(i)) continue;
|
if (graph.NotExistVertex(i)) continue;
|
||||||
|
@ -37,28 +37,28 @@ std::string DFAGraphToRegular(DFAGraph&& graph) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = n - 1; i > 1; --i) {
|
for (int i = cnt - 1; i > 1; --i) {
|
||||||
std::vector<std::vector<std::set<std::string>>> new_transitions(n,
|
std::vector<std::vector<std::set<std::string>>> new_transitions(cnt,
|
||||||
std::vector<std::set<std::string>>(n));
|
std::vector<std::set<std::string>>(cnt));
|
||||||
std::string loop = "";
|
std::string loop;
|
||||||
if (transitions[i][i].size() != 0) {
|
if (transitions[i][i].size() != 0) {
|
||||||
for (const std::string s: transitions[i][i]) {
|
for (const std::string& s: transitions[i][i]) {
|
||||||
loop += "(";
|
loop += "(";
|
||||||
loop += s;
|
loop += s;
|
||||||
loop += ")";
|
loop += ")";
|
||||||
loop += "|";
|
loop += "|";
|
||||||
}
|
}
|
||||||
if (loop.size())
|
if (loop.size()) {
|
||||||
loop.pop_back();
|
loop.pop_back();
|
||||||
if (transitions[i][i].size() > 1)
|
|
||||||
loop = "(" + loop + ")*";
|
loop = "(" + loop + ")*";
|
||||||
else
|
} else {
|
||||||
loop += "*";
|
loop = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < i; ++j) {
|
for (int j = 0; j < i; ++j) {
|
||||||
if (transitions[j][i].size() == 0) continue;
|
if (transitions[j][i].size() == 0) continue;
|
||||||
std::string j_to_i = "";
|
std::string j_to_i;
|
||||||
for (const std::string s: transitions[j][i]) {
|
for (const std::string s: transitions[j][i]) {
|
||||||
j_to_i += "(";
|
j_to_i += "(";
|
||||||
j_to_i += s;
|
j_to_i += s;
|
||||||
|
@ -67,13 +67,14 @@ std::string DFAGraphToRegular(DFAGraph&& graph) {
|
||||||
}
|
}
|
||||||
if (j_to_i.size())
|
if (j_to_i.size())
|
||||||
j_to_i.pop_back();
|
j_to_i.pop_back();
|
||||||
if (transitions[j][i].size() > 1)
|
else
|
||||||
|
continue;
|
||||||
j_to_i = "(" + j_to_i + ")";
|
j_to_i = "(" + j_to_i + ")";
|
||||||
|
|
||||||
for (int k = 0; k < i; ++k) {
|
for (int k = 0; k < i; ++k) {
|
||||||
if (transitions[i][k].size() == 0) continue;
|
if (transitions[i][k].size() == 0) continue;
|
||||||
std::string i_to_k = "";
|
std::string i_to_k = "";
|
||||||
for (const std::string s: transitions[i][k]) {
|
for (const std::string& s: transitions[i][k]) {
|
||||||
i_to_k += "(";
|
i_to_k += "(";
|
||||||
i_to_k += s;
|
i_to_k += s;
|
||||||
i_to_k += ")";
|
i_to_k += ")";
|
||||||
|
@ -81,8 +82,10 @@ std::string DFAGraphToRegular(DFAGraph&& graph) {
|
||||||
}
|
}
|
||||||
if (i_to_k.size())
|
if (i_to_k.size())
|
||||||
i_to_k.pop_back();
|
i_to_k.pop_back();
|
||||||
if (transitions[i][k].size() > 1)
|
else
|
||||||
i_to_k = "(" + j_to_i + ")";
|
continue;
|
||||||
|
i_to_k = "(" + i_to_k + ")";
|
||||||
|
|
||||||
|
|
||||||
new_transitions[j][k].insert(j_to_i + loop + i_to_k);
|
new_transitions[j][k].insert(j_to_i + loop + i_to_k);
|
||||||
}
|
}
|
||||||
|
@ -96,7 +99,7 @@ std::string DFAGraphToRegular(DFAGraph&& graph) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string loop;
|
std::string loop;
|
||||||
std::string begin_to_end;
|
std::string start_to_end;
|
||||||
|
|
||||||
if (transitions[1][1].size() != 0) {
|
if (transitions[1][1].size() != 0) {
|
||||||
for (const std::string& s: transitions[1][1]) {
|
for (const std::string& s: transitions[1][1]) {
|
||||||
|
@ -105,20 +108,22 @@ std::string DFAGraphToRegular(DFAGraph&& graph) {
|
||||||
loop += ")";
|
loop += ")";
|
||||||
loop += "|";
|
loop += "|";
|
||||||
}
|
}
|
||||||
if (loop.size())
|
if (loop.size()) {
|
||||||
loop.pop_back();
|
loop.pop_back();
|
||||||
loop = "(" + loop + ")*";
|
loop = "(" + loop + ")*";
|
||||||
|
} else {
|
||||||
|
loop = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (const std::string& s: transitions[1][0]) {
|
for (const std::string& s: transitions[1][0]) {
|
||||||
begin_to_end += "(";
|
start_to_end += "(";
|
||||||
begin_to_end += s;
|
start_to_end += s;
|
||||||
begin_to_end += ")";
|
start_to_end += ")";
|
||||||
begin_to_end += "|";
|
start_to_end += "|";
|
||||||
}
|
}
|
||||||
if (begin_to_end.size())
|
if (start_to_end.size())
|
||||||
begin_to_end.pop_back();
|
start_to_end.pop_back();
|
||||||
|
|
||||||
std::string res(loop + "(" + begin_to_end + ")");
|
return loop + "(" + start_to_end + ")";
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
70
src/main.cpp
70
src/main.cpp
|
@ -8,6 +8,11 @@
|
||||||
#include "converters/DFAToMinDFA.hpp"
|
#include "converters/DFAToMinDFA.hpp"
|
||||||
#include "converters/DFAToRegular.hpp"
|
#include "converters/DFAToRegular.hpp"
|
||||||
#include "converters/InvertFDFA.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 regular;
|
||||||
using namespace NFA;
|
using namespace NFA;
|
||||||
|
@ -49,60 +54,15 @@ void example2() {
|
||||||
dfa_graph.Print();
|
dfa_graph.Print();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
std::mt19937 rnd(1337);
|
||||||
{
|
|
||||||
RegularTree r("a*");
|
std::string GenerateRandomString(std::vector<char> alphabet, size_t len) {
|
||||||
NFAGraph NFA_graph = RegularToNFAGraph(std::move(r));
|
std::string res(len, ' ');
|
||||||
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_graph));
|
for (auto& i: res) {
|
||||||
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
i = alphabet[rnd() % alphabet.size()];
|
||||||
DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b'});
|
|
||||||
DFA_graph.Print();
|
|
||||||
DFA_graph.CreateDotFile("1.dot");
|
|
||||||
DFA_graph = InvertFDFAGraph(std::move(DFA_graph));
|
|
||||||
DFA_graph.CreateDotFile("2.dot");
|
|
||||||
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
return 0;
|
}
|
||||||
{
|
|
||||||
RegularTree r("((ab|ba)*( |a|ba))");
|
int main() {
|
||||||
NFAGraph NFA_tree = RegularToNFAGraph(std::move(r));
|
|
||||||
DFAGraph DFA_graph = NFAGraphToDFAGraph(std::move(NFA_tree));
|
|
||||||
// DFA_graph.CreateDotFile("1.dot");
|
|
||||||
// DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
|
||||||
DFA_graph = DFAGraphToFDFAGraph(std::move(DFA_graph), {'a', 'b'});
|
|
||||||
DFA_graph = InvertFDFAGraph(std::move(DFA_graph));
|
|
||||||
// DFA_graph.CreateDotFile("2.dot");
|
|
||||||
auto ss = DFAGraphToRegular(std::move(DFA_graph));
|
|
||||||
std::cout << ss << std::endl;
|
|
||||||
r = RegularTree(ss);
|
|
||||||
// r.Print();
|
|
||||||
std::cout << r.ToString() << std::endl;
|
|
||||||
// DFA_graph.Print();
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
DFA_graph = DFAGraphToMinDFAGraph(std::move(DFA_graph));
|
|
||||||
DFA_graph.Print();
|
|
||||||
auto s = DFAGraphToRegular(std::move(DFA_graph));
|
|
||||||
std::cout << s << std::endl;
|
|
||||||
r = RegularTree(s);
|
|
||||||
// r.Print();
|
|
||||||
std::cout << r.ToString() << std::endl;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
RegularTree r("a*");
|
|
||||||
auto nfa = RegularToNFAGraph(std::move(r));
|
|
||||||
auto dfa = NFAGraphToDFAGraph(std::move(nfa));
|
|
||||||
dfa = DFAGraphToMinDFAGraph(std::move(dfa));
|
|
||||||
auto fdfa = DFAGraphToFDFAGraph(std::move(dfa), {'a', 'b'});
|
|
||||||
fdfa.Print();
|
|
||||||
fdfa = InvertFDFAGraph(std::move(fdfa));
|
|
||||||
fdfa.Print();
|
|
||||||
dfa = DFAGraphToMinDFAGraph(std::move(fdfa));
|
|
||||||
auto s = DFAGraphToRegular(std::move(dfa));
|
|
||||||
|
|
||||||
/*
|
|
||||||
RegularTree r("(a|b)+bab(a|b)+");
|
|
||||||
std::cout << DFAGraphToRegular(DFAGraphToMinDFAGraph(InvertFDFAGraph(DFAGraphToFDFAGraph(DFAGraphToMinDFAGraph(NFAGraphToDFAGraph(RegularToNFAGraph(std::move(r)))), {'a', 'b'})))) << std::endl;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
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));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue