Skip to content

Commit

Permalink
Merge pull request #433 from VeriFIT/expand_alphabets
Browse files Browse the repository at this point in the history
Expand alphabets #patch
  • Loading branch information
Adda0 authored Aug 23, 2024
2 parents 9ab1675 + 35c903c commit 17ffaf6
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 18 deletions.
73 changes: 65 additions & 8 deletions include/mata/alphabet.hh
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ public:

bool operator==(const Alphabet &) const = delete;

virtual void clear() { throw std::runtime_error("Unimplemented"); }

protected:
virtual const void *address() const { return this; }
}; // class Alphabet.
Expand Down Expand Up @@ -115,6 +117,8 @@ public:

IntAlphabet& operator=(const IntAlphabet& int_alphabet) = delete;

void clear() override { throw std::runtime_error("Nonsensical use of clear() on IntAlphabet."); }

protected:
const void* address() const override { return &alphabet_instance; }

Expand Down Expand Up @@ -167,19 +171,20 @@ private:
class EnumAlphabet : public Alphabet {
public:
explicit EnumAlphabet() = default;
EnumAlphabet(const EnumAlphabet& rhs) = default;
EnumAlphabet(const EnumAlphabet& alphabet) = default;
explicit EnumAlphabet(const EnumAlphabet* const alphabet): EnumAlphabet(*alphabet) {}
EnumAlphabet(EnumAlphabet&& rhs) = default;

EnumAlphabet& operator=(const EnumAlphabet& rhs) = default;
EnumAlphabet& operator=(EnumAlphabet&& rhs) = default;

utils::OrdVector<Symbol> get_alphabet_symbols() const override { return symbols_; }
utils::OrdVector<Symbol> get_complement(const utils::OrdVector<Symbol>& symbols) const override {
return symbols_.difference(symbols);
}

std::string reverse_translate_symbol(Symbol symbol) const override;

private:
EnumAlphabet& operator=(const EnumAlphabet& rhs);

public:
/**
* @brief Expand alphabet by symbols from the passed @p symbols.
Expand Down Expand Up @@ -247,6 +252,28 @@ public:
* @param value The value of the newly added symbol.
*/
void update_next_symbol_value(Symbol value);

/**
* @brief Erase a symbol from the alphabet.
* @return Number of symbols erased (0 or 1).
*/
size_t erase(const Symbol symbol);

/**
* @brief Remove a symbol name value pair from the position @p pos from the alphabet.
* @return Iterator following the last removed element.
*/
void erase(utils::OrdVector<Symbol>::const_iterator pos) { symbols_.erase(pos); }

/**
* @brief Remove a symbol name value pair from the positions between @p first and @p last from the alphabet.
* @return Iterator following the last removed element.
*/
void erase(utils::OrdVector<Symbol>::const_iterator first, utils::OrdVector<Symbol>::const_iterator last) {
symbols_.erase(first, last);
}

void clear() override { symbols_.clear(); next_symbol_value_ = 0; }
}; // class EnumAlphabet.

/**
Expand All @@ -261,9 +288,14 @@ public:
using InsertionResult = std::pair<StringToSymbolMap::const_iterator, bool>;

explicit OnTheFlyAlphabet(Symbol init_symbol = 0) : next_symbol_value_(init_symbol) {};
OnTheFlyAlphabet(const OnTheFlyAlphabet& rhs) : symbol_map_(rhs.symbol_map_), next_symbol_value_(rhs.next_symbol_value_) {}
OnTheFlyAlphabet(const OnTheFlyAlphabet& alphabet) = default;
OnTheFlyAlphabet(OnTheFlyAlphabet&& alphabet) = default;
explicit OnTheFlyAlphabet(const OnTheFlyAlphabet* const alphabet): OnTheFlyAlphabet(*alphabet) {}
explicit OnTheFlyAlphabet(StringToSymbolMap str_sym_map) : symbol_map_(std::move(str_sym_map)) {}

OnTheFlyAlphabet& operator=(const OnTheFlyAlphabet& rhs) = default;
OnTheFlyAlphabet& operator=(OnTheFlyAlphabet&& rhs) = default;

/**
* Create alphabet from a list of symbol names.
* @param symbol_names Names for symbols on transitions.
Expand All @@ -288,9 +320,6 @@ public:

std::string reverse_translate_symbol(Symbol symbol) const override;

private:
OnTheFlyAlphabet& operator=(const OnTheFlyAlphabet& rhs);

public:
/**
* @brief Expand alphabet by symbols from the passed @p symbol_names.
Expand Down Expand Up @@ -375,6 +404,34 @@ public:
* @param value The value of the newly added symbol.
*/
void update_next_symbol_value(Symbol value);

/**
* @brief Remove a symbol name value pair specified by its @p symbol from the alphabet.
*
* @warning Complexity: O(n), where n is the number of symbols in the alphabet.
* @return Number of symbols removed (0 or 1).
*/
size_t erase(Symbol symbol);

/**
* @brief Remove a symbol name value pair specified by its @p symbol_name from the alphabet.
* @return Number of symbols removed (0 or 1).
*/
size_t erase(const std::string& symbol_name);

/**
* @brief Remove a symbol name value pair from the position @p pos from the alphabet.
*/
void erase(StringToSymbolMap::const_iterator pos) { symbol_map_.erase(pos); }

/**
* @brief Remove a symbol name value pair from the positions between @p first and @p last from the alphabet.
*/
void erase(StringToSymbolMap::const_iterator first, StringToSymbolMap::const_iterator last) {
symbol_map_.erase(first, last);
}

void clear() override { symbol_map_.clear(); next_symbol_value_ = 0; }
}; // class OnTheFlyAlphabet.
} // namespace mata

Expand Down
9 changes: 5 additions & 4 deletions include/mata/utils/ord-vector.hh
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ public:
virtual inline void reserve(size_t size) { vec_.reserve(size); }
virtual inline void resize(size_t size) { vec_.resize(size); }

virtual inline void erase(const_iterator first, const_iterator last) { vec_.erase(first, last); }
virtual inline iterator erase(const_iterator pos) { return vec_.erase(pos); }
virtual inline iterator erase(const_iterator first, const_iterator last) { return vec_.erase(first, last); }

virtual void insert(const Key& x) {
assert(is_sorted());
Expand Down Expand Up @@ -274,18 +275,18 @@ public:
*
* This function expects the vector to be sorted.
*/
inline void erase(const Key& k) {
inline size_t erase(const Key& k) {
assert(is_sorted());
auto found_value_it = std::lower_bound(vec_.begin(), vec_.end(), k);
if (found_value_it != vec_.end()) {
if (*found_value_it == k) {
vec_.erase(found_value_it);
assert(is_sorted());
return;
return 1;
}
}

throw std::runtime_error("Key is not in OrdVector.");
return 0;
}

virtual inline bool empty() const { return vec_.empty(); }
Expand Down
38 changes: 36 additions & 2 deletions src/alphabet.cc
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,47 @@ void mata::EnumAlphabet::add_new_symbol(const std::string& symbol) {
add_new_symbol(converted_symbol);
}

void mata::EnumAlphabet::add_new_symbol(Symbol symbol) {
void mata::EnumAlphabet::add_new_symbol(const Symbol symbol) {
symbols_.insert(symbol);
update_next_symbol_value(symbol);
}

void mata::EnumAlphabet::update_next_symbol_value(Symbol value) {
void mata::EnumAlphabet::update_next_symbol_value(const Symbol value) {
if (next_symbol_value_ <= value) {
next_symbol_value_ = value + 1;
}
}

size_t mata::EnumAlphabet::erase(const Symbol symbol) {
size_t num_of_erased{ symbols_.erase(symbol) };
if (symbol == next_symbol_value_ - 1) {
--next_symbol_value_;
}
return num_of_erased;
}

size_t mata::OnTheFlyAlphabet::erase(const Symbol symbol) {
const auto symbol_map_end = symbol_map_.end();
for (auto it = symbol_map_.begin(); it != symbol_map_end; ++it) {
if (it->second == symbol) {
if (symbol == next_symbol_value_ - 1) {
--next_symbol_value_;
}
symbol_map_.erase(it);
return 1;
}
}
return 0;
}

size_t mata::OnTheFlyAlphabet::erase(const std::string& symbol_name) {
auto found_it{ symbol_map_.find(symbol_name) };
if (found_it != symbol_map_.end()) {
if (found_it->second == next_symbol_value_ - 1) {
--next_symbol_value_;
}
symbol_map_.erase(found_it);
return 1;
}
return 0;
}
55 changes: 54 additions & 1 deletion tests/alphabet.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ TEST_CASE("mata::OnTheFlyAlphabet::add_symbols_from()") {
CHECK(alphabet.get_symbol_map() == OnTheFlyAlphabet::StringToSymbolMap{ { "a", 4 }, { "b", 2 }, { "c", 10 } });

alphabet.add_new_symbol("e", 7);
CHECK_THROWS_AS(alphabet.add_new_symbol("a", 0), std::runtime_error);
CHECK_THROWS(alphabet.add_new_symbol("a", 0));

symbols = alphabet.get_alphabet_symbols();
expected = mata::utils::OrdVector<Symbol>{ 7, 4, 2, 10 };
Expand All @@ -55,6 +55,34 @@ TEST_CASE("mata::OnTheFlyAlphabet::add_symbols_from()") {
CHECK(alphabet.get_symbol_map() == OnTheFlyAlphabet::StringToSymbolMap {
{ "a", 4 }, { "b", 2 }, { "c", 10 }, { "e", 7 }
});

OnTheFlyAlphabet alphabet2{ alphabet };
alphabet2.add_new_symbol("f", 42);
CHECK(alphabet.get_alphabet_symbols() != alphabet2.get_alphabet_symbols());
CHECK(alphabet.translate_symb("f") != 42);
CHECK(alphabet2.translate_symb("f") == 42);
size_t num_of_symbols{ alphabet.get_alphabet_symbols().size() };
alphabet.erase("e");
alphabet.erase("f");
CHECK(alphabet.get_alphabet_symbols().size() + 2 == num_of_symbols);

alphabet2 = alphabet;
alphabet2.add_new_symbol("f", 42);
CHECK(alphabet.get_alphabet_symbols() != alphabet2.get_alphabet_symbols());
CHECK(alphabet.translate_symb("f") != 42);
alphabet.erase("f");
CHECK(alphabet2.translate_symb("f") == 42);

OnTheFlyAlphabet alphabet_copy{ alphabet };
alphabet2 = OnTheFlyAlphabet{ std::move(alphabet) };
CHECK(alphabet2.get_alphabet_symbols() == alphabet_copy.get_alphabet_symbols());
alphabet = alphabet2;
alphabet2 = std::move(alphabet);
CHECK(alphabet2.get_alphabet_symbols() == alphabet_copy.get_alphabet_symbols());
alphabet = alphabet2;

alphabet.clear();
CHECK(alphabet.get_number_of_symbols() == 0);
}

TEST_CASE("mata::EnumAlphabet") {
Expand Down Expand Up @@ -91,4 +119,29 @@ TEST_CASE("mata::EnumAlphabet") {
CHECK(alphabet.translate_symb("1") == 1);
CHECK_THROWS(alphabet.translate_symb("3414not a number"));
CHECK_THROWS(alphabet.translate_symb("not a number"));

EnumAlphabet alphabet3{ alphabet };
alphabet3.add_new_symbol(42);
CHECK(alphabet.get_alphabet_symbols() != alphabet3.get_alphabet_symbols());
CHECK(alphabet3.get_number_of_symbols() == alphabet.get_number_of_symbols() + 1);
CHECK_THROWS(alphabet.translate_symb("42"));
CHECK(alphabet3.translate_symb("42") == 42);

alphabet3 = alphabet;
alphabet3.add_new_symbol(42);
CHECK(alphabet.get_alphabet_symbols() != alphabet3.get_alphabet_symbols());
CHECK(alphabet3.get_number_of_symbols() == alphabet.get_number_of_symbols() + 1);
CHECK_THROWS(alphabet.translate_symb("42"));
CHECK(alphabet3.translate_symb("42") == 42);

EnumAlphabet alphabet_copy{ alphabet };
alphabet3 = EnumAlphabet{ std::move(alphabet) };
CHECK(alphabet3.get_alphabet_symbols() == alphabet_copy.get_alphabet_symbols());
alphabet = alphabet3;
alphabet3 = std::move(alphabet);
CHECK(alphabet3.get_alphabet_symbols() == alphabet_copy.get_alphabet_symbols());
alphabet = std::move(alphabet3);

alphabet.clear();
CHECK(alphabet.get_number_of_symbols() == 0);
}
6 changes: 3 additions & 3 deletions tests/ord-vector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ TEST_CASE("mata::utils::OrdVector::erase()") {
CHECK(set == OrdVectorT{ 1, 2, 4, 6 });
set.erase(4);
CHECK(set == OrdVectorT{ 1, 2, 6 });
CHECK_THROWS(set.erase(5));
CHECK(set.erase(5) == 0);
set.erase(2);
CHECK(set == OrdVectorT{ 1, 6 });
set.erase(1);
Expand All @@ -25,11 +25,11 @@ TEST_CASE("mata::utils::OrdVector::erase()") {
CHECK(set == OrdVectorT{ 3 });
set.erase(3);
CHECK(set.empty());
CHECK_THROWS(set.erase(0));
CHECK(set.erase(0) == 0);
set.emplace_back(3);
set.emplace_back(4);
CHECK(set == OrdVectorT{ 3, 4 });
CHECK_THROWS(set.erase(0));
CHECK(set.erase(0) == 0);
}

TEST_CASE("mata::utils::OrdVector::front())") {
Expand Down

0 comments on commit 17ffaf6

Please sign in to comment.