Skip to content
Open
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
32 changes: 20 additions & 12 deletions include/mata/nft/nft.hh
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,21 @@ public:
// TODO: When there is a need for state dictionary, consider creating default library implementation of state
// dictionary in the attributes.

/**
* @brief If each level has its own alphabet. alphabets[i] (or rather alphabets->operator[](i)) contains a pointer to the alphabet of level i.
*
* Each Alphabet can be shared among multiple levels and NFTs. If all levels share the same alphabet, assign std::nullopt here and use alphabet member instead.
*/
std::optional<std::vector<Alphabet*>> alphabets = std::nullopt;

public:
explicit Nft(
Delta delta = {}, utils::SparseSet<State> initial_states = {},
utils::SparseSet<State> final_states = {}, Levels levels = {},
Alphabet* alphabet = nullptr)
Alphabet* alphabet = nullptr, std::optional<std::vector<Alphabet*>> alphabets = std::nullopt)
: Nfa{ std::move(delta), std::move(initial_states), std::move(final_states), alphabet },
levels{ levels.empty() ? Levels{ levels.num_of_levels, num_of_states(), DEFAULT_LEVEL } : std::move(levels) } {}
levels{ levels.empty() ? Levels{ levels.num_of_levels, num_of_states(), DEFAULT_LEVEL } : std::move(levels) },
alphabets{alphabets} {}

/**
* @brief Construct a new explicit NFT with num_of_states states and optionally set initial and final states.
Expand All @@ -153,32 +161,32 @@ public:
*/
explicit Nft(const size_t num_of_states, utils::SparseSet<State> initial_states = {},
utils::SparseSet<State> final_states = {}, Levels levels = {},
Alphabet* alphabet = nullptr)
Alphabet* alphabet = nullptr, std::optional<std::vector<Alphabet*>> alphabets = std::nullopt)
: Nfa{ num_of_states, std::move(initial_states), std::move(final_states), alphabet },
levels{ levels.empty() ? Levels{ levels.num_of_levels, num_of_states, DEFAULT_LEVEL } : std::move(levels) } {}
levels{ levels.empty() ? Levels{ levels.num_of_levels, num_of_states, DEFAULT_LEVEL } : std::move(levels) }, alphabets{alphabets} {}

static Nft with_levels(
Levels levels, const size_t num_of_states = 0, utils::SparseSet<State> initial_states = {},
utils::SparseSet<State> final_states = {}, Alphabet* alphabet = nullptr) {
return Nft{ num_of_states, std::move(initial_states), std::move(final_states), std::move(levels), alphabet };
utils::SparseSet<State> final_states = {}, Alphabet* alphabet = nullptr, std::optional<std::vector<Alphabet*>> alphabets = std::nullopt) {
return Nft{ num_of_states, std::move(initial_states), std::move(final_states), std::move(levels), alphabet, alphabets };
}

static Nft with_levels(
Levels levels, Delta delta, utils::SparseSet<State> initial_states = {},
utils::SparseSet<State> final_states = {}, Alphabet* alphabet = nullptr) {
return Nft{ std::move(delta), std::move(initial_states), std::move(final_states), std::move(levels), alphabet };
utils::SparseSet<State> final_states = {}, Alphabet* alphabet = nullptr, std::optional<std::vector<Alphabet*>> alphabets = std::nullopt) {
return Nft{ std::move(delta), std::move(initial_states), std::move(final_states), std::move(levels), alphabet, alphabets };
}

static Nft with_levels(
const size_t num_of_levels, const size_t num_of_states = 0, utils::SparseSet<State> initial_states = {},
utils::SparseSet<State> final_states = {}, Alphabet* alphabet = nullptr) {
return Nft{ num_of_states, std::move(initial_states), std::move(final_states), Levels{ num_of_levels }, alphabet };
utils::SparseSet<State> final_states = {}, Alphabet* alphabet = nullptr, std::optional<std::vector<Alphabet*>> alphabets = std::nullopt) {
return Nft{ num_of_states, std::move(initial_states), std::move(final_states), Levels{ num_of_levels }, alphabet, alphabets };
}

static Nft with_levels(
const size_t num_of_levels, Delta delta, utils::SparseSet<State> initial_states = {},
utils::SparseSet<State> final_states = {}, Alphabet* alphabet = nullptr) {
return Nft{ std::move(delta), std::move(initial_states), std::move(final_states), Levels{ num_of_levels }, alphabet };
utils::SparseSet<State> final_states = {}, Alphabet* alphabet = nullptr, std::optional<std::vector<Alphabet*>> alphabets = std::nullopt) {
return Nft{ std::move(delta), std::move(initial_states), std::move(final_states), Levels{ num_of_levels }, alphabet, alphabets };
}

/**
Expand Down
4 changes: 4 additions & 0 deletions src/nfa/operations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ Nfa mata::nfa::simple_revert(const Nfa& aut) {

result.initial = aut.final;
result.final = aut.initial;
result.alphabet = aut.alphabet;

return result;
}
Expand Down Expand Up @@ -1033,6 +1034,8 @@ Nfa mata::nfa::algorithms::minimize_hopcroft(const Nfa& dfa_trimmed) {
}
}

result.alphabet = dfa_trimmed.alphabet;

return result;
}

Expand Down Expand Up @@ -1199,6 +1202,7 @@ Nfa mata::nfa::determinize(
&& !(*macrostate_discover)(result, target_res, targets_orig)) { return result; }
}
}
result.alphabet = aut.alphabet;
return result;
}

Expand Down
1 change: 1 addition & 0 deletions src/nfa/product.cc
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ Nfa mata::nfa::algorithms::product(
}
}
}
product.alphabet = lhs.alphabet; // TODO is this the best choice?
return product;
} // intersection().

Expand Down
2 changes: 1 addition & 1 deletion src/nft/builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ Nft builder::from_nfa_with_levels_zero(
}

const size_t nfa_num_of_states{ nfa.num_of_states() };
Nft nft{ Nft::with_levels(num_of_levels, nfa_num_of_states, nfa.initial, nfa.final) };
Nft nft{ Nft::with_levels(num_of_levels, nfa_num_of_states, nfa.initial, nfa.final, nfa.alphabet) };

for(State src{ 0 }; src < nfa_num_of_states; ++src) {
for (const SymbolPost& symbol_post: nfa.delta[src]) {
Expand Down
3 changes: 3 additions & 0 deletions src/nft/intersection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ Nft mata::nft::algorithms::product(
}
}
}
// TODO is the following the best idea?
product.alphabet = lhs.alphabet;
product.alphabets = lhs.alphabets;
return product;
} // intersection().
} // namespace mata::nft.
27 changes: 26 additions & 1 deletion src/nft/nft.cc
Original file line number Diff line number Diff line change
Expand Up @@ -212,13 +212,38 @@ void Nft::print_to_dot(
}
};

auto has_alphabet_at_level = [&](const Level level) -> bool {
return this->alphabets.has_value() && this->alphabets->operator[](level) != nullptr;
};

auto translate_symbol_at_level = [&](const Symbol symbol, const Level level) -> std::string {
if (!decode_ascii_chars && has_alphabet_at_level(level)) {
return this->alphabets->operator[](level)->reverse_translate_symbol(symbol);
} else {
return translate_symbol(symbol);
}
};

auto vec_of_symbols_to_string = [&](const OrdVector<Symbol>& symbols) {
std::string result;
for (const Symbol& symbol : symbols) { result += translate_symbol(symbol) + ","; }
result.pop_back(); // Remove last comma
return result;
};

auto vec_of_symbols_to_string_at_level = [&](const OrdVector<Symbol>& symbols, const Level level) {
if (has_alphabet_at_level(level)) {
std::string result;
for (const Symbol& symbol: symbols) {
result += translate_symbol_at_level(symbol, level) + ",";
}
result.pop_back(); // Remove last comma
return result;
} else {
return vec_of_symbols_to_string(symbols);
}
};

auto vec_of_symbols_to_string_with_intervals = [&](const OrdVector<Symbol>& symbols) {
std::string result;

Expand Down Expand Up @@ -281,7 +306,7 @@ void Nft::print_to_dot(

std::string label = use_intervals
? vec_of_symbols_to_string_with_intervals(symbols)
: vec_of_symbols_to_string(symbols);
: vec_of_symbols_to_string_at_level(symbols, levels[source]);
std::string on_hover_label = replace_all(replace_all(label, "<", "&lt;"), ">", "&gt;");
bool is_shortened = false;
if (max_label_length > 0 && label.length() > static_cast<size_t>(max_label_length)) {
Expand Down
19 changes: 18 additions & 1 deletion src/nft/operations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -295,10 +295,16 @@ Nft mata::nft::project_out(const Nft& nft, const utils::OrdVector<Level>& levels
// project out x x x x
// new levels 0 0 1 2 2 0 0
std::vector<Level> new_levels(nft.levels.num_of_levels, 0);
std::vector<Level> old_levels {};
Level lvl_sub{ 0 };
for (Level lvl_old{ 0 }; lvl_old < seq_start_idx; lvl_old++) {
new_levels[lvl_old] = static_cast<Level>(lvl_old - lvl_sub);
if (levels_to_project.find(lvl_old) != levels_to_project.end()) { lvl_sub++; }
if (levels_to_project.find(lvl_old) != levels_to_project.end()) {
lvl_sub++;
} else {
old_levels.push_back(lvl_old);
assert(old_levels[new_levels[lvl_old]] == lvl_old);
}
}

// cannot use multimap, because it can contain multiple occurrences of (a -> a), (a -> a)
Expand Down Expand Up @@ -339,6 +345,7 @@ Nft mata::nft::project_out(const Nft& nft, const utils::OrdVector<Level>& levels

// Construct the automaton with projected levels.
Nft result{ Nft::with_levels(nft.levels, Delta{}, nft.initial, nft.final, nft.alphabet) };

for (State src_state{ 0 }; src_state < num_of_states_in_delta; src_state++) { // For every state.
for (const State cls_state : closure[src_state]) { // For every state in its epsilon closure.
if (nft.final[cls_state] && can_be_final(src_state)) result.final.insert(src_state);
Expand Down Expand Up @@ -373,6 +380,15 @@ Nft mata::nft::project_out(const Nft& nft, const utils::OrdVector<Level>& levels
for (State s{ 0 }; s < result.levels.size(); s++) { result.levels[s] = new_levels[result.levels[s]]; }
result.levels.num_of_levels = static_cast<Level>(result.levels.num_of_levels - levels_to_project.size());

if (nft.alphabets.has_value()) {
// retain all alphabets that are not projected out
std::vector<Alphabet*> alphabet_ptrs(new_levels.size(), nullptr);
for (size_t i{ 0 }; i < result.levels.num_of_levels; ++i) {
alphabet_ptrs[i] = nft.alphabets->operator[](old_levels[i]);
}
result.alphabets = std::make_optional<std::vector<Alphabet*>>(alphabet_ptrs);
}

return result;
}

Expand Down Expand Up @@ -1033,6 +1049,7 @@ Nft mata::nft::reduce(const Nft& aut, StateRenaming* state_renaming, const Param
Nft nft::determinize(const Nft& nft, std::unordered_map<StateSet, State>* subset_map) {
Nft result{ Nft::with_levels(nft.levels.num_of_levels) };
result.alphabet = nft.alphabet;
result.alphabets = nft.alphabets;
if (nft.initial.empty()) { return result; }

// Assuming all sets targets are non-empty.
Expand Down
Loading