Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MFA::Bisimilar fixes and more #351

Merged
merged 17 commits into from
Jun 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
MIT License

Copyright (c) 2022 Andrei Ilin, Alexander Delman, Kirill Shevchenko, Mikhail Teriukha, Anna Terentyeva, Danila
Knyazihin, Alina Chibizova, Edgar Makarov
Copyright (c) 2024 Aleksandr Delman, Anna Terentyeva, Danila Knyazihin, Antonina Nepeivoda, Mikhail Teriukha, Edgar
Makarov, Andrei Ilin, Kirill Shevchenko, Alina Chibizova, Lysenko Vasiliy, Sergey Dmitrievich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,13 @@ TG.generate_task(3, 5, false, false);
- `Complement: MFA -> MFA`
- `Deterministic: MFA -> Boolean`
- `Bisimilar: (MFA, MFA) -> OptionalBool`
- `Action: MFA -> NFA`
- `Symbolic: MFA -> NFA`
- `ActionBisimilar: (MFA, MFA) -> Boolean`
- `SymbolicBisimilar: (MFA, MFA) -> Boolean`
- `Equal: (MFA, MFA) -> Boolean`
- `MergeBisim: MFA -> MFA`
- `Equal: (BRefRegex, BRefRegex) -> Boolean`

**Метод Test**

Expand Down
40 changes: 32 additions & 8 deletions apps/MetamorphicTestsApp/src/MetamorphicTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ TEST(TestRegex, ToTxt) {
}

TEST(TestArden, RandomRegexEquivalence) {
RegexGenerator rg;
RegexGenerator rg(6, 3, 3, 2);
for (int i = 0; i < RegexNumber; i++) {
string rgx_str = rg.generate_regex();
SCOPED_TRACE("Regex: " + rgx_str);
Expand All @@ -43,7 +43,7 @@ TEST(TestArden, RandomRegexEquivalence) {
}
}

TEST(TestEqual, ThompsonGlushkov) {
TEST(TestNFA, EqualThompsonGlushkov) {
RegexGenerator rg;
for (int i = 0; i < RegexNumberX10; i++) {
string rgx_str = rg.generate_regex();
Expand Down Expand Up @@ -135,8 +135,9 @@ TEST(TestMFA, Fuzzing) {
for (int i = 0; i < RegexNumberX10; i++) {
string rgx_str = MetamorphicTests::generate_bregex(rg, 2);
SCOPED_TRACE("Regex: " + rgx_str);
MemoryFiniteAutomaton mfa1 = BackRefRegex(rgx_str).to_mfa();
MemoryFiniteAutomaton mfa2 = BackRefRegex(rgx_str).to_mfa_additional();
BackRefRegex r = BackRefRegex(rgx_str);
MemoryFiniteAutomaton mfa1 = r.to_mfa();
MemoryFiniteAutomaton mfa2 = r.to_mfa_additional();

MetamorphicTests::cmp_automatons(mfa1, mfa2);
}
Expand All @@ -154,9 +155,8 @@ TEST(TestMFA, Fuzzing) {

TEST(TestMFA, ToTxt) {
RegexGenerator rg(5, 3, 3, 2);
for (int i = 0; i < RegexNumberX10; i++) {
for (int i = 0; i < RegexNumber; i++) {
string rgx_str = MetamorphicTests::generate_bregex(rg, 2);
// std::cout << i << " " << rgx_str << "\n";
SCOPED_TRACE("Regex: " + rgx_str);
BackRefRegex r = BackRefRegex(rgx_str);
MemoryFiniteAutomaton mfa1 = r.to_mfa_additional();
Expand All @@ -166,7 +166,31 @@ TEST(TestMFA, ToTxt) {
}
}

TEST(TestBisimilar, MFA_Bisimilar) {
TEST(TestNFA, ToMFA) {
RegexGenerator rg(5, 3, 3, 2);
for (int i = 0; i < RegexNumber; i++) {
string rgx_str = MetamorphicTests::generate_bregex(rg, 2);
SCOPED_TRACE("Regex: " + rgx_str);
MemoryFiniteAutomaton mfa1 = BackRefRegex(rgx_str).to_mfa();
ASSERT_TRUE(MemoryFiniteAutomaton::equal(mfa1, mfa1.to_symbolic_fa().to_mfa()));
MemoryFiniteAutomaton mfa2 = BackRefRegex(rgx_str).to_mfa_additional();
ASSERT_TRUE(MemoryFiniteAutomaton::equal(mfa2, mfa2.to_symbolic_fa().to_mfa()));
}
}

TEST(TestMFA, ToFA) {
RegexGenerator rg(5, 3, 3, 2);
for (int i = 0; i < RegexNumber; i++) {
string rgx_str = rg.generate_regex();
SCOPED_TRACE("Regex: " + rgx_str);
Regex r = Regex(rgx_str);
FiniteAutomaton fa = r.to_glushkov();
ASSERT_TRUE(FiniteAutomaton::equal(fa, fa.to_mfa().to_action_fa()));
ASSERT_TRUE(FiniteAutomaton::equal(fa, fa.to_mfa().to_symbolic_fa()));
}
}

TEST(TestMFA, Bisimilar) {
RegexGenerator rg(5, 3, 3, 2);
for (int i = 0; i < RegexNumber; i++) {
string rgx_str = MetamorphicTests::generate_bregex(rg, 1);
Expand All @@ -180,7 +204,7 @@ TEST(TestBisimilar, MFA_Bisimilar) {
}
}

TEST(TestBisimilar, MFA_MergeBisimilar) {
TEST(TestMFA, MergeBisimilar) {
RegexGenerator rg(6, 3, 3, 2);
for (int i = 0; i < RegexNumber; i++) {
string rgx_str = MetamorphicTests::generate_bregex(rg, 2);
Expand Down
34 changes: 19 additions & 15 deletions apps/UnitTestsApp/src/UnitTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -766,14 +766,25 @@ TEST(TestBisimilar, MFA_Bisimilar) {
using Test = std::tuple<string, string, bool>;
vector<Test> tests = {
{"[aa*]:1a&1", "a[a*a]:1&1", true},
{"[a*]:1a*&1", "a*[a*]:1&1", false},
{"[aa*a*]:1a&1", "a[a*a*a]:1&1", true},
{"[ab]:2cab&2", "abc[ab]:2&2", true},
{"[a|b]:1c(a|b)&1", "(a|b)c[a|b]:1&1", false},
{"[a]:1*&1", "[a*]:1*&1", false},
{"[a*]:1&1", "[a*]:1a*&1", false},
{"[a*a*|]:1&1", "[a*]:1&1", true},
{"[a|a]:1*&1", "[a]:1*[a]:1*&1", true},
{"[a]:1*&1|[b]:1&1", "[b]:1&1|[a]:1*&1", true},
{"[a]:1&1(&1|[b]:1)*", "[a]:1&1(&1|[b]:1)*", true},
// перекрестная бисимуляция
{"[a*]:1a*&1", "a*[a*]:1&1", false},
{"b[a*]:1a*&1", "ba*[a*]:1&1", false},
{"b[a*]:1a*[a*]:1&1", "ba*[a*]:1a*&1", false},
{"b[a*]:1&1", "b[a*]:1a*&1", false},
// несовпадение раскрасок
{"[a]:1*&1", "[a*]:1*&1", false},
{"[a]:1*[a*]:1&1", "[a|]:1*&1", false},
// несовпадение по решающим действиям
{"[a|b]:1c(a|b)&1", "(a|b)c[a|b]:1&1", false},
// несовпадение CG
{"[aa]:1&1", "[|aa]:1&1", false},
{"[a*]:1a&1", "[a*a]:1&1", false},
};

for_each(tests.begin(), tests.end(), [](const Test& test) {
Expand Down Expand Up @@ -817,7 +828,8 @@ TEST(TestBisimilar, MFA_MergeBisimilar) {
MFAState(0,
"S",
false,
{{"a", {MFATransition(1, {1}, {})}}, {Symbol::Ref(1), {MFATransition(2)}}}));
{{"a", {MFATransition(1, {1}, {})}},
{Symbol::Ref(1), {MFATransition(2), MFATransition(2, {}, {}, {1})}}}));
ASSERT_EQ(
states[1],
MFAState(1,
Expand All @@ -829,7 +841,7 @@ TEST(TestBisimilar, MFA_MergeBisimilar) {

states =
BackRefRegex("(b|[&2*]:1*[a|&1]:2&2)*").to_mfa_additional().merge_bisimilar().get_states();
ASSERT_EQ(states.size(), 4);
ASSERT_EQ(states.size(), 3);
ASSERT_EQ(
states[0],
MFAState(0,
Expand All @@ -843,20 +855,12 @@ TEST(TestBisimilar, MFA_MergeBisimilar) {
ASSERT_EQ(
states[2],
MFAState(2,
"b.0, &2.4",
"S, b.0, &2.4",
true,
{{"b", {MFATransition(2)}},
{Symbol::Ref(2), {MFATransition(0, {1}, {})}},
{"a", {MFATransition(1, {2}, {}), MFATransition(1, {2}, {}, {1})}},
{Symbol::Ref(1), {MFATransition(1, {2}, {}), MFATransition(1, {2}, {}, {1})}}}));
ASSERT_EQ(states[3],
MFAState(3,
"S",
true,
{{"b", {MFATransition(2)}},
{Symbol::Ref(2), {MFATransition(0, {1}, {})}},
{"a", {MFATransition(1, {2}, {})}},
{Symbol::Ref(1), {MFATransition(1, {2}, {})}}}));
}

TEST(TestAmbiguity, AmbiguityValues) {
Expand Down
4 changes: 4 additions & 0 deletions libs/FuncLib/include/FuncLib/Functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,11 @@ inline static const std::vector<Function> functions = {
{"Equiv", {ObjectType::NFA, ObjectType::NFA}, ObjectType::Boolean},
{"Equal", {ObjectType::Regex, ObjectType::Regex}, ObjectType::Boolean},
{"Equal", {ObjectType::NFA, ObjectType::NFA}, ObjectType::Boolean},
{"Equal", {ObjectType::MFA, ObjectType::MFA}, ObjectType::Boolean},
{"Equal", {ObjectType::Int, ObjectType::Int}, ObjectType::Boolean},
{"Equal", {ObjectType::AmbiguityValue, ObjectType::AmbiguityValue}, ObjectType::Boolean},
{"Equal", {ObjectType::Boolean, ObjectType::Boolean}, ObjectType::Boolean},
{"Equal", {ObjectType::BRefRegex, ObjectType::BRefRegex}, ObjectType::Boolean},
{"OneUnambiguity", {ObjectType::Regex}, ObjectType::Boolean},
{"OneUnambiguity", {ObjectType::NFA}, ObjectType::Boolean},
{"SemDet", {ObjectType::NFA}, ObjectType::Boolean},
Expand All @@ -82,6 +84,8 @@ inline static const std::vector<Function> functions = {
{"ActionBisimilar", {ObjectType::MFA, ObjectType::MFA}, ObjectType::Boolean},
{"SymbolicBisimilar", {ObjectType::MFA, ObjectType::MFA}, ObjectType::Boolean},
{"MergeBisim", {ObjectType::MFA}, ObjectType::MFA},
{"Action", {ObjectType::MFA}, ObjectType::NFA},
{"Symbolic", {ObjectType::MFA}, ObjectType::NFA},
};

// вспомогательная функция для Ани и ее курсача
Expand Down
17 changes: 16 additions & 1 deletion libs/Interpreter/src/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ bool operator==(const Function& l, const Function& r) {
}

Interpreter::Interpreter() {
for (Function f : FuncLib::functions) {
for (const Function& f : FuncLib::functions) {
names_to_functions[f.name].push_back(f);
}

Expand Down Expand Up @@ -334,6 +334,15 @@ optional<GeneralObject> Interpreter::apply_function(const Function& function,
return ObjectBoolean(MemoryFiniteAutomaton::symbolic_bisimilar(
get<ObjectMFA>(arguments[0]).value, get<ObjectMFA>(arguments[1]).value, &log_template));
}
if (function.name == "Equal" && function.input[0] == ObjectType::MFA) {
return ObjectBoolean(MemoryFiniteAutomaton::equal(
get<ObjectMFA>(arguments[0]).value, get<ObjectMFA>(arguments[1]).value, &log_template));
}
if (function.name == "Equal" && function.input[0] == ObjectType::BRefRegex) {
return ObjectBoolean(BackRefRegex::equal(get<ObjectBRefRegex>(arguments[0]).value,
get<ObjectBRefRegex>(arguments[1]).value,
&log_template));
}
// # place for another diff types funcs

/*
Expand Down Expand Up @@ -448,6 +457,12 @@ optional<GeneralObject> Interpreter::apply_function(const Function& function,
if (function.name == "MergeBisim" && function.input[0] == ObjectType::MFA) {
res = ObjectMFA(get<ObjectMFA>(arguments[0]).value.merge_bisimilar(&log_template));
}
if (function.name == "Action") {
res = ObjectNFA(get<ObjectMFA>(arguments[0]).value.to_action_fa(&log_template));
}
if (function.name == "Symbolic") {
res = ObjectNFA(get<ObjectMFA>(arguments[0]).value.to_symbolic_fa(&log_template));
}
// # place for another same types funcs
if (function.name == "Intersect") {
res = ObjectNFA(FiniteAutomaton::intersection(
Expand Down
15 changes: 12 additions & 3 deletions libs/Objects/include/Objects/FiniteAutomaton.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ class FiniteAutomaton : public AbstractMachine {
const std::vector<int>&) const;
static bool equality_checker(const FiniteAutomaton& fa1, const FiniteAutomaton& fa2);
// дополнительно возвращает в векторах номера классов состояний каждого автомата
static std::pair<bool, std::vector<std::vector<int>>> bisimilarity_checker(
const FiniteAutomaton& fa1, const FiniteAutomaton& fa2);
static std::tuple<bool, std::pair<MetaInfo, MetaInfo>, std::vector<std::vector<int>>>
bisimilarity_checker(const FiniteAutomaton& fa1, const FiniteAutomaton& fa2);
// принимает в качестве лимита максимальное количество цифр в
// числителе + знаменателе дроби, которая может встретиться при вычислениях
AmbiguityValue get_ambiguity_value(
Expand All @@ -103,12 +103,21 @@ class FiniteAutomaton : public AbstractMachine {

std::vector<FAState::Transitions> get_reversed_transitions() const;

// заполняет стек состояниями в порядке выхода из них при обходе dfs,
// что необходимо для последующего построения SCC
void fill_order(int state_index, std::vector<bool>& visited, // NOLINT(runtime/references)
std::stack<int>& order // NOLINT(runtime/references)
);
// возвращает компоненты сильной связности
// возвращает компоненты сильной связности, алгоритм Косарайю
std::vector<std::unordered_set<int>> get_SCCs();

// отображает вспомогательные состояния Symbolic-NFA в действия над памятью
void to_mfa_dfs(int state_index,
std::vector<bool>& visited, // NOLINT(runtime/references)
std::vector<MFAState>& mfa_states, // NOLINT(runtime/references)
std::unordered_map<int, int>& states_mapping, // NOLINT(runtime/references)
MFATransition::MemoryActions memory_actions, int from_mfa_state) const;

FiniteAutomaton get_subautomaton(const CaptureGroup&);

public:
Expand Down
2 changes: 1 addition & 1 deletion libs/Objects/include/Objects/Language.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class Language {
std::optional<Regex_model> one_unambiguous_regex;

public:
Language();
Language() = default;
explicit Language(Alphabet alphabet);

static void enable_retrieving_from_cache();
Expand Down
41 changes: 41 additions & 0 deletions libs/Objects/include/Objects/MemoryCommon.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once
#include <iostream>
#include <optional>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
Expand All @@ -25,6 +27,45 @@ CellSet get_union(const CellSet& set1, const CellSet& set2);

CellSet get_intersection(const CellSet& set1, const CellSet& set2);

struct MFATransition {
enum MemoryAction {
// idle, ◇
open, // o
close, // c
reset, // r
};

using MemoryActions = std::unordered_map<int, MemoryAction>;

int to;
MemoryActions memory_actions;

explicit MFATransition(int to);
MFATransition(int, MemoryActions);
MFATransition(int, const std::unordered_set<int>&, const std::unordered_set<int>&);
MFATransition(int, const std::unordered_set<int>&, const std::unordered_set<int>&,
const std::unordered_set<int>&);

struct TransitionConfig {
// пары {номер ячейки, линеаризованный номер оператора}
const CellSet* destination_first;
const std::unordered_set<int>* source_in_lin_cells;
const std::unordered_set<int>* iteration_over_cells;
// пары {номер ячейки, линеаризованный номер оператора}
const CellSet* source_last;
const std::unordered_set<int>* destination_in_lin_cells;
const CellSet* to_reset;
};
MFATransition(int, const TransitionConfig& config);

std::string get_actions_str() const;
bool operator==(const MFATransition& other) const;

struct Hasher {
std::size_t operator()(const MFATransition&) const;
};
};

struct CaptureGroup {
struct State {
int index;
Expand Down
Loading
Loading