Skip to content

Commit

Permalink
(#279) fixed arden test, added auto alphabet generating (new AlgExpre…
Browse files Browse the repository at this point in the history
…ssion constructor)
  • Loading branch information
xendalm committed Nov 24, 2023
1 parent bec1d3c commit 4bd2149
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 143 deletions.
12 changes: 6 additions & 6 deletions apps/UnitTestsApp/src/UnitTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,13 +363,13 @@ TEST(TestCaseName, Test_remove_trap) {
ASSERT_EQ(fa3.size(), fa3.remove_trap_states().size()); // Кейс, когда ловушек нет.
}

TEST(TestCaseName, Test_arden) {
TEST(TestArden, Test_to_regex_equivalence) {
auto test_equivalence = [](const string& rgx_str) {
Regex reg(rgx_str);
ASSERT_TRUE(Regex::equivalent(reg, reg.to_thompson().to_regex()));
ASSERT_TRUE(Regex::equivalent(reg, reg.to_glushkov().to_regex()));
ASSERT_TRUE(Regex::equivalent(reg, reg.to_ilieyu().to_regex()));
ASSERT_TRUE(Regex::equivalent(reg, reg.to_antimirov().to_regex()));
Regex r1(rgx_str), r2(rgx_str);
ASSERT_TRUE(Regex::equivalent(r1, r2.to_thompson().to_regex()));
ASSERT_TRUE(Regex::equivalent(r1, r2.to_glushkov().to_regex()));
ASSERT_TRUE(Regex::equivalent(r1, r2.to_ilieyu().to_regex()));
ASSERT_TRUE(Regex::equivalent(r1, r2.to_antimirov().to_regex()));
};

test_equivalence("a");
Expand Down
17 changes: 8 additions & 9 deletions libs/Objects/include/Objects/AlgExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,18 @@ class AlgExpression : public BaseObject {

// копирует объект (!!! не чистит память !!!)
virtual void copy(const AlgExpression*) = 0; // NOLINT(build/include_what_you_use)
// возвращает указатель на 'new' объект соответствующего типа
// возвращает указатель на 'new' объект своего типа
virtual AlgExpression* make() const = 0;

void clear();

// Создает новый язык с алфавитом
void set_language(const std::set<Symbol>& _alphabet);
// Рекурсивная генерация алфавита
void generate_alphabet(std::set<Symbol>& _alphabet); // NOLINT(runtime/references)
// Генерация языка из алфавита
// Устанавливает язык
void set_language(const std::shared_ptr<Language>& _language);
// Рекурсивная генерация алфавита во всех нодах
void generate_alphabet();
// Генерация алфавита и создание нового языка
void make_language();

// для print_tree
Expand Down Expand Up @@ -115,15 +117,12 @@ class AlgExpression : public BaseObject {
std::vector<AlgExpression*> get_last_nodes();
std::unordered_map<int, std::vector<int>> pairs() const;

void regex_union(AlgExpression* a, AlgExpression* b);
void regex_alt(AlgExpression* a, AlgExpression* b);
void regex_star(AlgExpression* a);
void regex_eps();

public:
AlgExpression();
AlgExpression(std::shared_ptr<Language>, Type, const Lexeme&, const std::set<Symbol>&);
AlgExpression(std::set<Symbol>); // NOLINT(runtime/explicit)
AlgExpression(Type type, AlgExpression* = nullptr,
AlgExpression* = nullptr); // NOLINT(runtime/explicit)

virtual ~AlgExpression();

Expand Down
2 changes: 2 additions & 0 deletions libs/Objects/include/Objects/BackRefRegex.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class BackRefRegex : public AlgExpression {
public:
BackRefRegex() = default;
BackRefRegex(const std::string&); // NOLINT(runtime/explicit)
BackRefRegex(Type type, AlgExpression* = nullptr,
AlgExpression* = nullptr); // NOLINT(runtime/explicit)

BackRefRegex* make_copy() const override;
BackRefRegex(const BackRefRegex&);
Expand Down
3 changes: 0 additions & 3 deletions libs/Objects/include/Objects/FiniteAutomaton.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,6 @@ class FiniteAutomaton : public AbstractMachine {
// функция проверки на семантическую детерминированность
bool semdet_entry(bool annoted = false, iLogTemplate* log = nullptr) const;

static std::vector<expression_arden> arden(const std::vector<expression_arden>& in, int index);
static std::vector<expression_arden> arden_minimize(const std::vector<expression_arden>& in);

public:
FiniteAutomaton();
FiniteAutomaton(int initial_state, std::vector<State> states,
Expand Down
2 changes: 2 additions & 0 deletions libs/Objects/include/Objects/Regex.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ class Regex : public AlgExpression {
Regex() = default;
Regex(const std::string&); // NOLINT(runtime/explicit)
Regex(const std::string&, const std::shared_ptr<Language>&);
Regex(Type type, AlgExpression* = nullptr,
AlgExpression* = nullptr); // NOLINT(runtime/explicit)

Regex* make_copy() const override;
Regex(const Regex&) = default;
Expand Down
60 changes: 29 additions & 31 deletions libs/Objects/src/AlgExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ AlgExpression::AlgExpression(std::shared_ptr<Language> language, Type type, cons

AlgExpression::AlgExpression(set<Symbol> alphabet) : BaseObject(std::move(alphabet)) {}

AlgExpression::AlgExpression(Type type, AlgExpression* _term_l, AlgExpression* _term_r)
: type(type) {
if (_term_l) {
term_l = _term_l->make_copy();
alphabet = term_l->alphabet;
}
if (_term_r) {
term_r = _term_r->make_copy();
alphabet.insert(term_r->alphabet.begin(), term_r->alphabet.end());
}
}

AlgExpression::Lexeme::Lexeme(Type type, const Symbol& symbol, int number)
: type(type), symbol(symbol), number(number) {}

Expand Down Expand Up @@ -68,20 +80,28 @@ void AlgExpression::set_language(const set<Symbol>& _alphabet) {
language = make_shared<Language>(alphabet);
}

void AlgExpression::generate_alphabet(set<Symbol>& _alphabet) {
void AlgExpression::set_language(const std::shared_ptr<Language>& _language) {
language = _language;
}

void AlgExpression::generate_alphabet() {
if (type == AlgExpression::symb) {
alphabet = {value.symbol};
return;
}
alphabet.clear();
if (term_l != nullptr) {
term_l->generate_alphabet(alphabet);
term_l->generate_alphabet();
alphabet = term_l->alphabet;
}
if (term_r != nullptr) {
term_r->generate_alphabet(alphabet);
}
for (const auto& symb : alphabet) {
_alphabet.insert(symb);
term_r->generate_alphabet();
alphabet.insert(term_r->alphabet.begin(), term_r->alphabet.end());
}
}

void AlgExpression::make_language() {
generate_alphabet(alphabet);
generate_alphabet();
language = make_shared<Language>(alphabet);
}

Expand Down Expand Up @@ -480,7 +500,7 @@ AlgExpression* AlgExpression::scan_conc(const vector<AlgExpression::Lexeme>& lex
p->term_l = l;
p->term_r = r;
p->value = lexemes[i];
p->type = conc;
p->type = Type::conc;

p->alphabet = l->alphabet;
p->alphabet.insert(r->alphabet.begin(), r->alphabet.end());
Expand Down Expand Up @@ -533,7 +553,6 @@ AlgExpression* AlgExpression::scan_alt(const vector<AlgExpression::Lexeme>& lexe
p = make();
p->term_l = l;
p->term_r = r;

p->value = lexemes[i];
p->type = Type::alt;

Expand Down Expand Up @@ -607,7 +626,7 @@ bool AlgExpression::equality_checker(const AlgExpression* expr1, const AlgExpres
return true;
if (expr1 == nullptr || expr2 == nullptr)
return false;
if (expr1->value.type != expr2->value.type)
if (expr1->type != expr2->type)
return false;

if (expr1->value.type == Lexeme::Type::symb) {
Expand Down Expand Up @@ -750,25 +769,4 @@ unordered_map<int, vector<int>> AlgExpression::pairs() const {
break;
}
return {};
}

void AlgExpression::regex_union(AlgExpression* a, AlgExpression* b) {
type = Type::conc;
term_l = a->make_copy();
term_r = b->make_copy();
}

void AlgExpression::regex_alt(AlgExpression* a, AlgExpression* b) {
type = Type::alt;
term_l = a->make_copy();
term_r = b->make_copy();
}

void AlgExpression::regex_star(AlgExpression* a) {
type = Type::star;
term_l = a->make_copy();
}

void AlgExpression::regex_eps() {
type = Type::eps;
}
3 changes: 3 additions & 0 deletions libs/Objects/src/BackRefRegex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ BackRefRegex::BackRefRegex(const BackRefRegex& other) : AlgExpression(other) {
cell_number = other.cell_number;
}

BackRefRegex::BackRefRegex(Type type, AlgExpression* term_l, AlgExpression* term_r)
: AlgExpression(type, term_l, term_r) {}

void BackRefRegex::copy(const AlgExpression* other) {
auto* tmp = cast(other);
alphabet = tmp->alphabet;
Expand Down
106 changes: 16 additions & 90 deletions libs/Objects/src/FiniteAutomaton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2394,74 +2394,6 @@ bool FiniteAutomaton::is_empty() const {
— Ах! Рефакторинг, рефакторинг! - и умирает.
*/

vector<expression_arden> FiniteAutomaton::arden_minimize(const vector<expression_arden>& in) {
map<int, Regex*> out_map;
// Загоняем все в map, потом пишем в вектор (объединяем переходы из 1
// состояния)
for (auto i : in) {
if (!out_map.count(i.fa_state_number)) {
out_map[i.fa_state_number] = Regex::cast(i.regex_from_state->make_copy());
} else {
auto* temp = new Regex();
temp->regex_alt(i.regex_from_state, out_map[i.fa_state_number]);
delete out_map[i.fa_state_number];
out_map[i.fa_state_number] = temp;
}
}
vector<expression_arden> out;
for (const auto& cur_elem : out_map) {
expression_arden temp = {cur_elem.first, cur_elem.second};
out.push_back(temp);
}
return out;
}

vector<expression_arden> FiniteAutomaton::arden(const vector<expression_arden>& in, int index) {
vector<expression_arden> out;
// ищем переход из текущего состояния
int indexcur = -1;
for (int i = 0; (i < in.size() && indexcur == -1); i++) {
if (in[i].fa_state_number == index) {
indexcur = i;
}
}
// если таких переходов нет
if (indexcur == -1) {
for (auto i : in) {
Regex* r = Regex::cast(i.regex_from_state->make_copy());
expression_arden temp = {i.fa_state_number, r};
out.push_back(temp);
}
return out;
}
// если есть только такой переход
if (in.size() < 2) {
auto* r = new Regex();
r->regex_star(in[0].regex_from_state);
expression_arden temp = {-1, r};
out.push_back(temp);
return out;
}
// добавляем (текущий переход)* к всем остальным
for (int i = 0; i < in.size(); i++) {
if (i != indexcur) {
auto* r = new Regex();
r->regex_star(in[indexcur].regex_from_state);
Regex* k;
if (in[i].regex_from_state->to_txt().empty()) {
k = Regex::cast(r->make_copy());
} else {
k = new Regex();
k->regex_union(in[i].regex_from_state, r);
}
delete r;
expression_arden temp = {in[i].fa_state_number, k};
out.push_back(temp);
}
}
return out;
}

Regex FiniteAutomaton::to_regex(iLogTemplate* log) const {
if (log) {
log->set_parameter("oldautomaton", *this);
Expand All @@ -2471,7 +2403,7 @@ Regex FiniteAutomaton::to_regex(iLogTemplate* log) const {
std::unordered_map<int, std::unordered_map<int, Regex>> SLAE{};
// индекс стартового состояния (должен быть среди состояний)
const int start_state_index = initial_state;
// индекс глобального конечного состояния (должен не быть среди состоянтй)
// индекс глобального конечного состояния (должен не быть среди состояний)
const int end_state_index = -1;
/*
@algorithm_sample
Expand Down Expand Up @@ -2504,9 +2436,8 @@ Regex FiniteAutomaton::to_regex(iLogTemplate* log) const {

for (int state_index_to : states_to) {
if (SLAE[state.index].count(state_index_to)) {
Regex new_regex{};
new_regex.regex_alt(&SLAE[state.index][state_index_to], &symbol_regex);
SLAE[state.index][state_index_to] = new_regex;
SLAE[state.index][state_index_to] =
Regex(Regex::Type::alt, &SLAE[state.index][state_index_to], &symbol_regex);
} else {
SLAE[state.index].insert({state_index_to, symbol_regex});
}
Expand All @@ -2521,20 +2452,17 @@ Regex FiniteAutomaton::to_regex(iLogTemplate* log) const {
return;
}

// случай отсутсвия в уранении переходов в себя
// случай отсутствия в уравнении переходов в себя
if (!SLAE[state_index].count(state_index)) {
return;
}

// подготавливаем звёздную регулярку
Regex state_self_regex{};
state_self_regex.regex_star(&SLAE[state_index][state_index]);
Regex state_self_regex(Regex::Type::star, &SLAE[state_index][state_index]);

// добавление звёздного перехода к остальным переходам уранения
// добавление звёздного перехода к остальным переходам уравнения
for (auto& [state_index_to, to_regex] : SLAE[state_index]) {
Regex new_regex{};
new_regex.regex_union(&state_self_regex, &to_regex);
to_regex = new_regex;
to_regex = Regex(Regex::Type::conc, &state_self_regex, &to_regex);
}

// удаление рассмотренного перехода состояния в себя же
Expand All @@ -2547,7 +2475,7 @@ Regex FiniteAutomaton::to_regex(iLogTemplate* log) const {
// ссылка не константная, тк уравнения
// будут подвержены изменениям

// начальное состояние должно остаться посленим не рассмотренным
// начальное состояние должно остаться последним не рассмотренным
if (state_index_row == start_state_index) {
continue;
}
Expand All @@ -2556,7 +2484,7 @@ Regex FiniteAutomaton::to_regex(iLogTemplate* log) const {
arden_theorem(state_index_row);

// подстановка рассматриваемого уравнения в его упоминания в прочих
// итерация по всем уравнениям с переходами в исходное для подстановки регулярки
// итерациях по всем уравнениям с переходами в исходное для подстановки регулярки
for (auto& [state_index_from, equation_from] : SLAE) {
// пропуск итерации, если в рассматриваемом уравнения нет исходного
if (!equation_from.count(state_index_row)) {
Expand All @@ -2566,14 +2494,12 @@ Regex FiniteAutomaton::to_regex(iLogTemplate* log) const {
// итерация по всем переходам из исходного уравнения
for (auto& [state_index_col, regex_col] : equation_row) {
// регулярка перехода из рассматриваемого уравнения в исходное
Regex regex_from{};
regex_from.regex_union(&equation_from[state_index_row], &regex_col);
Regex regex_from = Regex(Regex::Type::conc, &equation_from[state_index_row], &regex_col);

// объединяем полученную регулярку с имеющейся в рассматривамом уравнении
// объединяем полученную регулярку с имеющейся в рассматриваемом уравнении
if (equation_from.count(state_index_col)) {
Regex new_regex{};
new_regex.regex_alt(&equation_from[state_index_col], &regex_from);
equation_from[state_index_col] = new_regex;
equation_from[state_index_col] =
Regex(Regex::Type::alt, &equation_from[state_index_col], &regex_from);
} else {
equation_from.insert({state_index_col, regex_from});
}
Expand All @@ -2594,16 +2520,16 @@ Regex FiniteAutomaton::to_regex(iLogTemplate* log) const {
if (SLAE.count(start_state_index) && SLAE[start_state_index].count(end_state_index)) {
auto& result_regex = SLAE[start_state_index][end_state_index];

// явная подстановка нужного языка в финальную регулярку
result_regex.language = language;
// подстановка нужного языка в финальную регулярку
result_regex.set_language(language);

if (log) {
log->set_parameter("result", result_regex.to_txt());
}
return result_regex;
}

// случай недостижимости ни одного из конечных состояний или их отсуствия
// случай недостижимости ни одного из конечных состояний или их отсутствия
if (log) {
log->set_parameter("result", "Unknown");
}
Expand Down
Loading

0 comments on commit 4bd2149

Please sign in to comment.