From 2cc505ee05985d982c2ecef06377d8ee8b564e19 Mon Sep 17 00:00:00 2001 From: koniksedy Date: Fri, 1 Mar 2024 16:20:41 +0100 Subject: [PATCH 1/3] nfa::Nfa::insert_word() and nfa::Nfa::insert_word_by_parts() can have optional target word --- include/mata/nfa/nfa.hh | 4 +- include/mata/nft/nft.hh | 8 +- src/nfa/nfa.cc | 16 ++- src/nft/nft.cc | 28 +++-- tests/nfa/nfa.cc | 101 ++++++++++++--- tests/nft/nft.cc | 267 ++++++++++++++++++++++++++++++++++++---- 6 files changed, 359 insertions(+), 65 deletions(-) diff --git a/include/mata/nfa/nfa.hh b/include/mata/nfa/nfa.hh index e9aa8aefa..69e070ba4 100644 --- a/include/mata/nfa/nfa.hh +++ b/include/mata/nfa/nfa.hh @@ -109,9 +109,9 @@ public: * * @param src The source state where the word begins. It must already be a part of the automaton. * @param word The nonempty word to be inserted into the NFA. - * @param tgt The target state where the word ends. It must already be a part of the automaton. + * @param tgt The target state where the word ends. If set to Limits::max_state, the word ends in a new state. */ - void insert_word(const State src, const Word &word, const State tgt); + State insert_word(const State src, const Word &word, const State tgt = Limits::max_state); /** * @brief Get the current number of states in the whole automaton. diff --git a/include/mata/nft/nft.hh b/include/mata/nft/nft.hh index 95fba48ce..b5978bbe8 100644 --- a/include/mata/nft/nft.hh +++ b/include/mata/nft/nft.hh @@ -152,9 +152,9 @@ public: * * @param src The source state where the word begins. It must already be a part of the transducer. * @param word The nonempty word to be inserted into the NFA. - * @param tgt The target state where the word ends. It must already be a part of the transducer. + * @param tgt The target state where the word ends. If set to Limits::max_state, the word ends in a new state. */ - void insert_word(const State src, const Word &word, const State tgt); + State insert_word(const State src, const Word &word, const State tgt = Limits::max_state); /** * Inserts a word, which is created by interleaving parts from @p word_part_on_level, into the NFT @@ -167,9 +167,9 @@ public: * * @param src The source state where the word begins. This state must already exist in the transducer and must be of a level 0. * @param word_part_on_level The vector of word parts, with each part corresponding to a different level. - * @param tgt The target state where the word ends. This state must already exist in the transducer and must be of a level 0. + * @param tgt The target state where the word ends. If set to Limits::max_state, the word ends in a new state. */ - void insert_word_by_parts(const State src, const std::vector &word_part_on_level, const State tgt); + State insert_word_by_parts(const State src, const std::vector &word_part_on_level, const State tgt = Limits::max_state); /** * Inserts an identity transition into the NFT. diff --git a/src/nfa/nfa.cc b/src/nfa/nfa.cc index 40d5a5719..927a9d4f5 100644 --- a/src/nfa/nfa.cc +++ b/src/nfa/nfa.cc @@ -544,15 +544,19 @@ State Nfa::add_state(State state) { return state; } -void Nfa::insert_word(const State src, const Word &word, const State tgt) { +State Nfa::insert_word(const State src, const Word &word, const State tgt) { assert(!word.empty()); assert(src < num_of_states()); - assert(tgt < num_of_states()); const size_t word_len = word.size(); if (word_len == 1) { + if (tgt == Limits::max_state) { + State new_tgt = add_state(); + delta.add(src, word[0], new_tgt); + return new_tgt; + } delta.add(src, word[0], tgt); - return; + return tgt; } // Add transition src --> inner_state. @@ -568,7 +572,13 @@ void Nfa::insert_word(const State src, const Word &word, const State tgt) { } // Add transition inner_state --> tgt + if (tgt == Limits::max_state) { + State new_tgt = add_state(); + delta.add(prev_state, word[word_len - 1], new_tgt); + return new_tgt; + } delta.add(prev_state, word[word_len - 1], tgt); + return tgt; } size_t Nfa::num_of_states() const { diff --git a/src/nft/nft.cc b/src/nft/nft.cc index 0200a8f5a..4edc59555 100644 --- a/src/nft/nft.cc +++ b/src/nft/nft.cc @@ -305,37 +305,33 @@ State Nft::add_state_with_level(const State state, const Level level) { return Nfa::add_state(state); } -void Nft::insert_word(const State src, const Word &word, const State tgt) { +State Nft::insert_word(const State src, const Word &word, const State tgt) { assert(0 < num_of_levels); const State first_new_state = num_of_states(); - Nfa::insert_word(src, word, tgt); + const State word_tgt = Nfa::insert_word(src, word, tgt); const size_t num_of_states_after = num_of_states(); const Level src_lvl = levels[src]; + Level lvl = (num_of_levels == 1 ) ? src_lvl : (src_lvl + 1); State state{ first_new_state }; for (; state < num_of_states_after; state++, lvl = (lvl + 1) % static_cast(num_of_levels)){ add_state_with_level(state, lvl); } - assert(levels[tgt] == 0 || levels[num_of_states_after - 1] < levels[tgt]); -} + assert(levels[word_tgt] == 0 || levels[num_of_states_after - 1] < levels[word_tgt]); -void Nft::insert_identity(const State state, const Symbol symbol) { - insert_word(state, Word(num_of_levels, symbol), state); + return word_tgt; } -void Nft::insert_word_by_parts(const State src, const std::vector &word_part_on_level, const State tgt) { +State Nft::insert_word_by_parts(const State src, const std::vector &word_part_on_level, const State tgt) { assert(0 < num_of_levels); assert(word_part_on_level.size() == num_of_levels); assert(src < num_of_states()); - assert(tgt < num_of_states()); assert(levels[src] == 0); - assert(levels[tgt] == 0); if (num_of_levels == 1) { - Nft::insert_word(src, word_part_on_level[0], tgt); - return; + return Nft::insert_word(src, word_part_on_level[0], tgt); } size_t max_word_part_len = std::max_element( @@ -377,7 +373,17 @@ void Nft::insert_word_by_parts(const State src, const std::vector &word_pa } // Add transition inner_state --> tgt. + if (tgt == Limits::max_state) { + State new_tgt = add_state_with_level(0); + delta.add(prev_state, get_next_symbol(prev_lvl), new_tgt); + return new_tgt; + } delta.add(prev_state, get_next_symbol(prev_lvl), tgt); + return tgt; +} + +void Nft::insert_identity(const State state, const Symbol symbol) { + insert_word(state, Word(num_of_levels, symbol), state); } void Nft::clear() { diff --git a/tests/nfa/nfa.cc b/tests/nfa/nfa.cc index 7a04c7ad6..68930fa1b 100644 --- a/tests/nfa/nfa.cc +++ b/tests/nfa/nfa.cc @@ -3001,7 +3001,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("Insert 'a'") { SECTION("src < tgt") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(1, {'a'}, 3); + State new_tgt = nfa.insert_word(1, {'a'}, 3); + CHECK(new_tgt == 3); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(1, 'a', 3); @@ -3011,7 +3012,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("src < tgt && final.contains(tgt)") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(1, {'a'}, 4); + State new_tgt = nfa.insert_word(1, {'a'}, 4); + CHECK(new_tgt == 4); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(1, 'a', 4); @@ -3021,7 +3023,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("tgt < src") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(3, {'a'}, 1); + State new_tgt = nfa.insert_word(3, {'a'}, 1); + CHECK(new_tgt == 1); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(3, 'a', 1); @@ -3032,7 +3035,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("tgt < src && final.contains(tgt)") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(4, {'a'}, 1); + State new_tgt = nfa.insert_word(4, {'a'}, 1); + CHECK(new_tgt == 1); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(4, 'a', 1); @@ -3042,7 +3046,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("self-loop") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(3, {'a'}, 3); + State new_tgt = nfa.insert_word(3, {'a'}, 3); + CHECK(new_tgt == 3); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(3, 'a', 3); @@ -3052,19 +3057,35 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("self-loop && final.contains(tgt)") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(4, {'a'}, 4); + State new_tgt = nfa.insert_word(4, {'a'}, 4); + CHECK(new_tgt == 4); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(4, 'a', 4); CHECK(are_equivalent(nfa, expected)); } + + SECTION("tgt is not specified") { + nfa = Nfa(delta, { 0 }); + State new_tgt = nfa.insert_word(1, {'a'}); + nfa.final.insert(new_tgt); + + expected = Nfa(3, { 0 }, { 2 }); + expected.delta.add(0, 0, 1); + expected.delta.add(0, 4, 0); + expected.delta.add(1, 5, 1); + expected.delta.add(1, 'a', 2); + + CHECK(are_equivalent(nfa, expected)); + } } SECTION("Insert 'ab'") { SECTION("src < tgt") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(1, {'a', 'b'}, 3); + State new_tgt = nfa.insert_word(1, {'a', 'b'}, 3); + CHECK(new_tgt == 3); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(1, 'a', 5); @@ -3075,7 +3096,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("src < tgt && final.contains(tgt)") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(1, {'a', 'b'}, 4); + State new_tgt = nfa.insert_word(1, {'a', 'b'}, 4); + CHECK(new_tgt == 4); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(1, 'a', 5); @@ -3086,7 +3108,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("tgt < src") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(3, {'a', 'b'}, 1); + State new_tgt = nfa.insert_word(3, {'a', 'b'}, 1); + CHECK(new_tgt == 1); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(3, 'a', 5); @@ -3098,7 +3121,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("tgt < src && final.contains(tgt)") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(4, {'a', 'b'}, 1); + State new_tgt = nfa.insert_word(4, {'a', 'b'}, 1); + CHECK(new_tgt == 1); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(4, 'a', 5); @@ -3109,7 +3133,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("self-loop") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(3, {'a', 'b'}, 3); + State new_tgt = nfa.insert_word(3, {'a', 'b'}, 3); + CHECK(new_tgt == 3); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(3, 'a', 5); @@ -3120,7 +3145,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("self-loop && final.contains(tgt)") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(4, {'a', 'b'}, 4); + State new_tgt = nfa.insert_word(4, {'a', 'b'}, 4); + CHECK(new_tgt == 4); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(4, 'a', 5); @@ -3128,12 +3154,29 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { CHECK(are_equivalent(nfa, expected)); } + + SECTION("tgt is not specified") { + nfa = Nfa(delta, { 0 }); + State new_tgt = nfa.insert_word(1, {'a', 'b'}); + nfa.final.insert(new_tgt); + + expected = Nfa(4, { 0 }, { 3 }); + expected.delta.add(0, 0, 1); + expected.delta.add(0, 4, 0); + expected.delta.add(1, 5, 1); + expected.delta.add(1, 'a', 2); + expected.delta.add(2, 'b', 3); + + CHECK(are_equivalent(nfa, expected)); + } + } SECTION("Insert 'abcd'") { SECTION("src < tgt") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(1, {'a', 'b', 'c', 'd'}, 3); + State new_tgt = nfa.insert_word(1, {'a', 'b', 'c', 'd'}, 3); + CHECK(new_tgt == 3); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(1, 'a', 5); @@ -3146,7 +3189,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("src < tgt && final.contains(tgt)") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(1, {'a', 'b', 'c', 'd'}, 4); + State new_tgt = nfa.insert_word(1, {'a', 'b', 'c', 'd'}, 4); + CHECK(new_tgt == 4); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(1, 'a', 5); @@ -3159,7 +3203,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("tgt < src") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(3, {'a', 'b', 'c', 'd'}, 1); + State new_tgt = nfa.insert_word(3, {'a', 'b', 'c', 'd'}, 1); + CHECK(new_tgt == 1); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(3, 'a', 5); @@ -3173,7 +3218,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("tgt < src && final.contains(tgt)") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(4, {'a', 'b', 'c', 'd'}, 1); + State new_tgt = nfa.insert_word(4, {'a', 'b', 'c', 'd'}, 1); + CHECK(new_tgt == 1); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(4, 'a', 5); @@ -3186,7 +3232,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("self-loop") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(3, {'a', 'b', 'c', 'd'}, 3); + State new_tgt = nfa.insert_word(3, {'a', 'b', 'c', 'd'}, 3); + CHECK(new_tgt == 3); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(3, 'a', 5); @@ -3199,7 +3246,8 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { SECTION("self-loop && final.contains(tgt)") { nfa = Nfa(delta, { 0 }, { 4 }); - nfa.insert_word(4, {'a', 'b', 'c', 'd'}, 4); + State new_tgt = nfa.insert_word(4, {'a', 'b', 'c', 'd'}, 4); + CHECK(new_tgt == 4); expected = Nfa(delta, { 0 }, { 4 }); expected.delta.add(4, 'a', 5); @@ -3209,5 +3257,22 @@ TEST_CASE("mata::nfa::Nfa::insert_word()") { CHECK(are_equivalent(nfa, expected)); } + + SECTION("tgt is not specified") { + nfa = Nfa(delta, { 0 }); + State new_tgt = nfa.insert_word(1, {'a', 'b', 'c', 'd'}); + nfa.final.insert(new_tgt); + + expected = Nfa(6, { 0 }, { 5 }); + expected.delta.add(0, 0, 1); + expected.delta.add(0, 4, 0); + expected.delta.add(1, 5, 1); + expected.delta.add(1, 'a', 2); + expected.delta.add(2, 'b', 3); + expected.delta.add(3, 'c', 4); + expected.delta.add(4, 'd', 5); + + CHECK(are_equivalent(nfa, expected)); + } } } diff --git a/tests/nft/nft.cc b/tests/nft/nft.cc index c4451d0ac..98c07983f 100644 --- a/tests/nft/nft.cc +++ b/tests/nft/nft.cc @@ -4283,7 +4283,8 @@ TEST_CASE("mata::nft::Nft::insert_word()") { SECTION("Insert 'a'") { SECTION("num_of_levels == 1") { nft = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0 }, 1); - nft.insert_word(1, {'a'}, 3); + State new_tgt = nft.insert_word(1, {'a'}, 3); + CHECK(new_tgt == 3); expected = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0 }, 1); expected.delta.add(1, 'a', 3); @@ -4293,7 +4294,8 @@ TEST_CASE("mata::nft::Nft::insert_word()") { SECTION("num_of_levels == 3") { nft = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0 }, 3); - nft.insert_word(1, {'a'}, 3); + State new_tgt = nft.insert_word(1, {'a'}, 3); + CHECK(new_tgt == 3); expected = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0 }, 3); expected.delta.add(1, 'a', 3); @@ -4303,7 +4305,8 @@ TEST_CASE("mata::nft::Nft::insert_word()") { SECTION("self-loop, num_of_levels == 1") { nft = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0 }, 1); - nft.insert_word(3, {'a'}, 3); + State new_tgt = nft.insert_word(3, {'a'}, 3); + CHECK(new_tgt == 3); expected = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0 }, 1); expected.delta.add(3, 'a', 3); @@ -4313,7 +4316,8 @@ TEST_CASE("mata::nft::Nft::insert_word()") { SECTION("self-loop, num_of_levels == 3") { nft = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0 }, 3); - nft.insert_word(3, {'a'}, 3); + State new_tgt = nft.insert_word(3, {'a'}, 3); + CHECK(new_tgt == 3); expected = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0 }, 3); expected.delta.add(3, 'a', 3); @@ -4321,12 +4325,27 @@ TEST_CASE("mata::nft::Nft::insert_word()") { CHECK(are_equivalent(nft, expected)); } + SECTION("tgt is not specified") { + nft = Nft(delta, { 0 }, {}, { 0, 0, 0, 0, 0 }, 1); + State new_tgt = nft.insert_word(1, {'a'}); + nft.final.insert(new_tgt); + + expected = Nft(3, { 0 }, { 2 }, { 0, 0, 0, 0}, 1); + expected.delta.add(0, 0, 1); + expected.delta.add(0, 4, 0); + expected.delta.add(1, 5, 1); + expected.delta.add(1, 'a', 2); + + CHECK(are_equivalent(nft, expected)); + } + } SECTION("Insert 'ab'") { SECTION("num_of_levels == 1") { nft = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0 }, 1); - nft.insert_word(1, {'a', 'b'}, 3); + State new_tgt = nft.insert_word(1, {'a', 'b'}, 3); + CHECK(new_tgt == 3); expected = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0, 0 }, 1); expected.delta.add(1, 'a', 5); @@ -4337,7 +4356,8 @@ TEST_CASE("mata::nft::Nft::insert_word()") { SECTION("num_of_levels == 3") { nft = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0 }, 3); - nft.insert_word(1, {'a', 'b'}, 3); + State new_tgt = nft.insert_word(1, {'a', 'b'}, 3); + CHECK(new_tgt == 3); expected = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0, 1 }, 3); expected.delta.add(1, 'a', 5); @@ -4348,7 +4368,8 @@ TEST_CASE("mata::nft::Nft::insert_word()") { SECTION("self-loop, num_of_levels == 1") { nft = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0 }, 1); - nft.insert_word(3, {'a', 'b'}, 3); + State new_tgt = nft.insert_word(3, {'a', 'b'}, 3); + CHECK(new_tgt == 3); expected = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0, 0 }, 1); expected.delta.add(3, 'a', 5); @@ -4359,7 +4380,8 @@ TEST_CASE("mata::nft::Nft::insert_word()") { SECTION("self-loop, num_of_levels == 3") { nft = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0 }, 3); - nft.insert_word(3, {'a', 'b'}, 3); + State new_tgt = nft.insert_word(3, {'a', 'b'}, 3); + CHECK(new_tgt == 3); expected = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0, 1 }, 3); expected.delta.add(3, 'a', 5); @@ -4367,12 +4389,28 @@ TEST_CASE("mata::nft::Nft::insert_word()") { CHECK(are_equivalent(nft, expected)); } + + SECTION("tgt is not specified") { + nft = Nft(delta, { 0 }, {}, { 0, 0, 0, 0, 0 }, 1); + State new_tgt = nft.insert_word(1, {'a', 'b'}); + nft.final.insert(new_tgt); + + expected = Nft(4, { 0 }, { 3 }, { 0, 0, 0, 0, 0 }, 1); + expected.delta.add(0, 0, 1); + expected.delta.add(0, 4, 0); + expected.delta.add(1, 5, 1); + expected.delta.add(1, 'a', 2); + expected.delta.add(2, 'b', 3); + + CHECK(are_equivalent(nft, expected)); + } } SECTION("Insert 'abcd'") { SECTION("num_of_levels == 1") { nft = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0}, 1); - nft.insert_word(1, {'a', 'b', 'c', 'd'}, 3); + State new_tgt = nft.insert_word(1, {'a', 'b', 'c', 'd'}, 3); + CHECK(new_tgt == 3); expected = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0, 0, 0, 0}, 1); expected.delta.add(1, 'a', 5); @@ -4385,7 +4423,8 @@ TEST_CASE("mata::nft::Nft::insert_word()") { SECTION("num_of_levels == 3") { nft = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0}, 3); - nft.insert_word(1, {'a', 'b', 'c', 'd'}, 3); + State new_tgt = nft.insert_word(1, {'a', 'b', 'c', 'd'}, 3); + CHECK(new_tgt == 3); expected = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0, 1, 2, 0}, 3); expected.delta.add(1, 'a', 5); @@ -4398,7 +4437,8 @@ TEST_CASE("mata::nft::Nft::insert_word()") { SECTION("self-loop, num_of_levels == 1") { nft = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0}, 1); - nft.insert_word(3, {'a', 'b', 'c', 'd'}, 3); + State new_tgt = nft.insert_word(3, {'a', 'b', 'c', 'd'}, 3); + CHECK(new_tgt == 3); expected = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0, 0, 0, 0}, 1); expected.delta.add(3, 'a', 5); @@ -4411,7 +4451,8 @@ TEST_CASE("mata::nft::Nft::insert_word()") { SECTION("self-loop, num_of_levels == 3") { nft = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0}, 3); - nft.insert_word(3, {'a', 'b', 'c', 'd'}, 3); + State new_tgt = nft.insert_word(3, {'a', 'b', 'c', 'd'}, 3); + CHECK(new_tgt == 3); expected = Nft(delta, { 0 }, { 4 }, { 0, 0, 0, 0, 0, 1, 2, 0}, 3); expected.delta.add(3, 'a', 5); @@ -4421,6 +4462,23 @@ TEST_CASE("mata::nft::Nft::insert_word()") { CHECK(are_equivalent(nft, expected)); } + + SECTION("tgt is not specified") { + nft = Nft(delta, { 0 }, {}, { 0, 0, 0, 0, 0 }, 1); + State new_tgt = nft.insert_word(1, {'a', 'b', 'c', 'd'}); + nft.final.insert(new_tgt); + + expected = Nft(6, { 0 }, { 5 }, { 0, 0, 0, 0, 0, 0, 0 }, 1); + expected.delta.add(0, 0, 1); + expected.delta.add(0, 4, 0); + expected.delta.add(1, 5, 1); + expected.delta.add(1, 'a', 2); + expected.delta.add(2, 'b', 3); + expected.delta.add(3, 'c', 4); + expected.delta.add(4, 'd', 5); + + CHECK(are_equivalent(nft, expected)); + } } } @@ -4563,7 +4621,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("num_of_levels == 1 && word_part.size() == 1") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 1); - nft.insert_word_by_parts(0, { {'a'} } , 1); + State new_tgt = nft.insert_word_by_parts(0, { {'a'} } , 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 1); expected.delta.add(0, 'a', 1); @@ -4573,7 +4632,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("num_of_levels == 1 && word_part.size() == 2") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 1); - nft.insert_word_by_parts(0, { {'a', 'b'} } , 1); + State new_tgt = nft.insert_word_by_parts(0, { {'a', 'b'} } , 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 0 }, 1); expected.delta.add(0, 'a', 2); @@ -4584,7 +4644,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("num_of_levels == 1 && word_part.size() == 4") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 0, 0, 0 }, 1); - nft.insert_word_by_parts(0, { {'a', 'b', 'c', 'd'} }, 1); + State new_tgt = nft.insert_word_by_parts(0, { {'a', 'b', 'c', 'd'} }, 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 0, 0, 0 }, 1); expected.delta.add(0, 'a', 2); @@ -4607,7 +4668,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("word_part.size() == 1") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 2); - nft.insert_word_by_parts(0, { {'a'}, {'b'} } , 1); + State new_tgt = nft.insert_word_by_parts(0, { {'a'}, {'b'} } , 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 1 }, 2); expected.delta.add(0, 'a', 2); @@ -4617,7 +4679,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("word_part.size() == 2") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 2); - nft.insert_word_by_parts(0, { {'a', 'b'}, {'c', 'd'} } , 1); + State new_tgt = nft.insert_word_by_parts(0, { {'a', 'b'}, {'c', 'd'} } , 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 1, 0, 1 }, 2); expected.delta.add(0, 'a', 2); @@ -4630,7 +4693,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("word_part.size() == 4") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 2); - nft.insert_word_by_parts(0, { {'a', 'b', 'c', 'd'}, {'e', 'f', 'g', 'h'} }, 1); + State new_tgt = nft.insert_word_by_parts(0, { {'a', 'b', 'c', 'd'}, {'e', 'f', 'g', 'h'} }, 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 1, 0, 1, 0, 1, 0, 1 }, 2); expected.delta.add(0, 'a', 2); @@ -4650,7 +4714,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("word_part.size() == 1") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 4); - nft.insert_word_by_parts(0, { {'a'}, {'b'}, {'c'}, {'d'} }, 1); + State new_tgt = nft.insert_word_by_parts(0, { {'a'}, {'b'}, {'c'}, {'d'} }, 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 1, 2, 3 }, 4); expected.delta.add(0, 'a', 2); @@ -4663,7 +4728,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("word_part.size() == 2") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 4); - nft.insert_word_by_parts(0, { {'a', 'b'}, {'c', 'd'}, {'e', 'f'}, {'g', 'h'} }, 1); + State new_tgt = nft.insert_word_by_parts(0, { {'a', 'b'}, {'c', 'd'}, {'e', 'f'}, {'g', 'h'} }, 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 1, 2, 3, 0, 1, 2, 3 }, 4); expected.delta.add(0, 'a', 2); @@ -4680,7 +4746,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("word_part.size() == 4") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 4); - nft.insert_word_by_parts(0, { {'a', 'b', 'c', 'd'}, {'e', 'f', 'g', 'h'}, {'i', 'j', 'k', 'l'}, {'m', 'n', 'o', 'p'} }, 1); + State new_tgt = nft.insert_word_by_parts(0, { {'a', 'b', 'c', 'd'}, {'e', 'f', 'g', 'h'}, {'i', 'j', 'k', 'l'}, {'m', 'n', 'o', 'p'} }, 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 }, 4); expected.delta.add(0, 'a', 2); @@ -4705,6 +4772,146 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { } } + SECTION("The target state is not specified.") { + Delta delta; + delta.add(0, 'w', 0); + delta.add(0, 'y', 1); + delta.add(1, 'x', 1); + delta.add(1, 'z', 0); + + SECTION("num_of_levels == 2") { + SECTION("word_part.size() == 1") { + nft = Nft(delta, { 0, 1 }, {}, { 0, 0 }, 2); + State new_tgt = nft.insert_word_by_parts(0, { {'a'}, {'b'} }); + nft.final.insert(new_tgt); + + expected = Nft(delta, { 0, 1 }, { 3 }, { 0, 0, 1, 0 }, 2); + expected.delta.add(0, 'a', 2); + expected.delta.add(2, 'b', 3); + + CHECK(are_equivalent(nft, expected)); + } + + SECTION("word_part.size() == 2") { + nft = Nft(delta, { 0, 1 }, {}, { 0, 0 }, 2); + State new_tgt = nft.insert_word_by_parts(0, { {'a', 'b'}, {'c', 'd'} }); + nft.final.insert(new_tgt); + + expected = Nft(delta, { 0, 1 }, { 5 }, { 0, 0, 1, 0, 1, 0 }, 2); + expected.delta.add(0, 'a', 2); + expected.delta.add(2, 'c', 3); + expected.delta.add(3, 'b', 4); + expected.delta.add(4, 'd', 5); + + CHECK(are_equivalent(nft, expected)); + } + + SECTION("word_part.size() == 4") { + nft = Nft(delta, { 0, 1 }, {}, { 0, 0 }, 2); + State new_tgt = nft.insert_word_by_parts(0, { {'a', 'b', 'c', 'd'}, {'e', 'f', 'g', 'h'} }); + nft.final.insert(new_tgt); + + expected = Nft(delta, { 0, 1 }, { 9 }, { 0, 0, 1, 0, 1, 0, 1, 0, 1, 0 }, 2); + expected.delta.add(0, 'a', 2); + expected.delta.add(2, 'e', 3); + expected.delta.add(3, 'b', 4); + expected.delta.add(4, 'f', 5); + expected.delta.add(5, 'c', 6); + expected.delta.add(6, 'g', 7); + expected.delta.add(7, 'd', 8); + expected.delta.add(8, 'h', 9); + + CHECK(are_equivalent(nft, expected)); + } + } + + SECTION("num_of_levels == 4") { + SECTION("word_part.size() == 1") { + nft = Nft(delta, { 0, 1 }, {}, { 0, 0 }, 4); + State new_tgt = nft.insert_word_by_parts(0, { {'a'}, {'b'}, {'c'}, {'d'} }); + nft.final.insert(new_tgt); + + expected = Nft(delta, { 0, 1 }, { 5 }, { 0, 0, 1, 2, 3, 0 }, 4); + expected.delta.add(0, 'a', 2); + expected.delta.add(2, 'b', 3); + expected.delta.add(3, 'c', 4); + expected.delta.add(4, 'd', 5); + + CHECK(are_equivalent(nft, expected)); + } + + SECTION("word_part.size() == 2") { + nft = Nft(delta, { 0, 1 }, {}, { 0, 0 }, 4); + State new_tgt = nft.insert_word_by_parts(0, { {'a', 'b'}, {'c', 'd'}, {'e', 'f'}, {'g', 'h'} }); + nft.final.insert(new_tgt); + + expected = Nft(delta, { 0, 1 }, { 9 }, { 0, 0, 1, 2, 3, 0, 1, 2, 3, 0 }, 4); + expected.delta.add(0, 'a', 2); + expected.delta.add(2, 'c', 3); + expected.delta.add(3, 'e', 4); + expected.delta.add(4, 'g', 5); + expected.delta.add(5, 'b', 6); + expected.delta.add(6, 'd', 7); + expected.delta.add(7, 'f', 8); + expected.delta.add(8, 'h', 9); + + CHECK(are_equivalent(nft, expected)); + } + + SECTION("word_part.size() == 4") { + nft = Nft(delta, { 0, 1 }, {}, { 0, 0 }, 4); + State new_tgt = nft.insert_word_by_parts(0, { {'a', 'b', 'c', 'd'}, {'e', 'f', 'g', 'h'}, {'i', 'j', 'k', 'l'}, {'m', 'n', 'o', 'p'} }); + nft.final.insert(new_tgt); + + expected = Nft(delta, { 0, 1 }, { 17 }, { 0, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0 }, 4); + expected.delta.add(0, 'a', 2); + expected.delta.add(2, 'e', 3); + expected.delta.add(3, 'i', 4); + expected.delta.add(4, 'm', 5); + expected.delta.add(5, 'b', 6); + expected.delta.add(6, 'f', 7); + expected.delta.add(7, 'j', 8); + expected.delta.add(8, 'n', 9); + expected.delta.add(9, 'c', 10); + expected.delta.add(10, 'g', 11); + expected.delta.add(11, 'k', 12); + expected.delta.add(12, 'o', 13); + expected.delta.add(13, 'd', 14); + expected.delta.add(14, 'h', 15); + expected.delta.add(15, 'l', 16); + expected.delta.add(16, 'p', 17); + + CHECK(are_equivalent(nft, expected)); + } + + SECTION("The lengths of word pats dont have the same length.") { + nft = Nft(delta, { 0, 1 }, {}, { 0, 0 }, 4); + State new_tgt = nft.insert_word_by_parts(0, { {'a', 'b'}, {'e', 'f', 'g', 'h'}, {'i', 'j', 'k', 'l'}, {} }); + nft.final.insert(new_tgt); + + expected = Nft(delta, { 0, 1 }, { 17 }, { 0, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0 }, 4); + expected.delta.add(0, 'a', 2); + expected.delta.add(2, 'e', 3); + expected.delta.add(3, 'i', 4); + expected.delta.add(4, EPSILON, 5); + expected.delta.add(5, 'b', 6); + expected.delta.add(6, 'f', 7); + expected.delta.add(7, 'j', 8); + expected.delta.add(8, EPSILON, 9); + expected.delta.add(9, EPSILON, 10); + expected.delta.add(10, 'g', 11); + expected.delta.add(11, 'k', 12); + expected.delta.add(12, EPSILON, 13); + expected.delta.add(13, EPSILON, 14); + expected.delta.add(14, 'h', 15); + expected.delta.add(15, 'l', 16); + expected.delta.add(16, EPSILON, 17); + + CHECK(are_equivalent(nft, expected)); + } + } + } + SECTION("The lengths of word parts dont have to match.") { Delta delta; delta.add(0, 'w', 0); @@ -4715,7 +4922,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("num_of_levels == 2") { SECTION("word_part.size() == 1") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 2); - nft.insert_word_by_parts(0, { {}, {'b'} } , 1); + State new_tgt = nft.insert_word_by_parts(0, { {}, {'b'} } , 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 1 }, 2); expected.delta.add(0, EPSILON, 2); @@ -4726,7 +4934,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("word_part.size() == 2") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 2); - nft.insert_word_by_parts(0, { {'a', 'b'}, {'c'} } , 1); + State new_tgt = nft.insert_word_by_parts(0, { {'a', 'b'}, {'c'} } , 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 1, 0, 1 }, 2); expected.delta.add(0, 'a', 2); @@ -4739,7 +4948,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("word_part.size() == 4") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 2); - nft.insert_word_by_parts(0, { {'a', 'b', 'c', 'd'}, {'e'} }, 1); + State new_tgt = nft.insert_word_by_parts(0, { {'a', 'b', 'c', 'd'}, {'e'} }, 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 1, 0, 1, 0, 1, 0, 1 }, 2); expected.delta.add(0, 'a', 2); @@ -4758,7 +4968,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("num_of_levels == 4") { SECTION("word_part.size() == 1") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 4); - nft.insert_word_by_parts(0, { {'a'}, {}, {'c'}, {} }, 1); + State new_tgt = nft.insert_word_by_parts(0, { {'a'}, {}, {'c'}, {} }, 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 1, 2, 3 }, 4); expected.delta.add(0, 'a', 2); @@ -4771,7 +4982,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("word_part.size() == 2") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 4); - nft.insert_word_by_parts(0, { {'a'}, {'c', 'd'}, {}, {'g'} }, 1); + State new_tgt = nft.insert_word_by_parts(0, { {'a'}, {'c', 'd'}, {}, {'g'} }, 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 1, 2, 3, 0, 1, 2, 3 }, 4); expected.delta.add(0, 'a', 2); @@ -4788,7 +5000,8 @@ TEST_CASE("mata::nft::Nft::insert_word_by_parts()") { SECTION("word_part.size() == 4") { nft = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0 }, 4); - nft.insert_word_by_parts(0, { {}, {'e', 'f'}, {'i', 'j', 'k', 'l'}, {'m', 'n', 'o', 'p'} }, 1); + State new_tgt = nft.insert_word_by_parts(0, { {}, {'e', 'f'}, {'i', 'j', 'k', 'l'}, {'m', 'n', 'o', 'p'} }, 1); + CHECK(new_tgt == 1); expected = Nft(delta, { 0, 1 }, { 0, 1 }, { 0, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 }, 4); expected.delta.add(0, EPSILON, 2); From 557dbfc9ab168c5f19fce25e411d6cf81ff7a547 Mon Sep 17 00:00:00 2001 From: koniksedy Date: Sun, 3 Mar 2024 15:46:51 +0100 Subject: [PATCH 2/3] Overload of nft::Nft::insert_identity(), for a vector of symbols, is done. --- include/mata/nft/nft.hh | 8 ++++ src/nft/nft.cc | 6 +++ tests/nft/nft.cc | 83 +++++++++++++++++++++++++++++++---------- 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/include/mata/nft/nft.hh b/include/mata/nft/nft.hh index b5978bbe8..44ab65cfc 100644 --- a/include/mata/nft/nft.hh +++ b/include/mata/nft/nft.hh @@ -171,6 +171,14 @@ public: */ State insert_word_by_parts(const State src, const std::vector &word_part_on_level, const State tgt = Limits::max_state); + /** + * Inserts identity transitions into the NFT. + * + * @param state The state where the identity transition will be inserted. This serves as both the source and target state. + * @param symbol The vector of symbols used for the identity transition. Identity will be created for each symbol in the vector. + */ + void insert_identity(const State state, const std::vector &symbols); + /** * Inserts an identity transition into the NFT. * diff --git a/src/nft/nft.cc b/src/nft/nft.cc index 4edc59555..a52175038 100644 --- a/src/nft/nft.cc +++ b/src/nft/nft.cc @@ -382,6 +382,12 @@ State Nft::insert_word_by_parts(const State src, const std::vector &word_p return tgt; } +void Nft::insert_identity(const State state, const std::vector &symbols) { + for (const Symbol symbol : symbols) { + insert_identity(state, symbol); + } +} + void Nft::insert_identity(const State state, const Symbol symbol) { insert_word(state, Word(num_of_levels, symbol), state); } diff --git a/tests/nft/nft.cc b/tests/nft/nft.cc index 98c07983f..4b039492c 100644 --- a/tests/nft/nft.cc +++ b/tests/nft/nft.cc @@ -4537,37 +4537,82 @@ TEST_CASE("mata::nft::Nft::insert_identity()") { delta.add(1, 'b', 2); SECTION("num_of_levels == 1") { - nft = Nft(delta, { 0 }, { 2 }, { 0, 0, 0 }, 1); - nft.insert_identity(1, 'c'); - expected = Nft(delta, { 0 }, { 2 }, { 0, 0, 0 }, 1); - expected.delta.add(1, 'c', 1); + SECTION("symbols cnt == 1") { + nft = Nft(delta, { 0 }, { 2 }, { 0, 0, 0 }, 1); + nft.insert_identity(1, 'c'); - CHECK(are_equivalent(nft, expected)); + expected = Nft(delta, { 0 }, { 2 }, { 0, 0, 0 }, 1); + expected.delta.add(1, 'c', 1); + + CHECK(are_equivalent(nft, expected)); + } + + SECTION("symbols cnt == 2") { + nft = Nft(delta, { 0 }, { 2 }, { 0, 0, 0 }, 1); + nft.insert_identity(1, {'c', 'd'}); + + expected = Nft(delta, { 0 }, { 2 }, { 0, 0, 0, 1 }, 1); + expected.insert_identity(1, 'c'); + expected.insert_identity(1, 'd'); + + CHECK(are_equivalent(nft, expected)); + } } SECTION("num_of_levels == 2") { - nft = Nft(delta, { 0 }, { 2 }, { 0, 0, 0 }, 2); - nft.insert_identity(1, 'c'); - expected = Nft(delta, { 0 }, { 2 }, { 0, 0, 0, 1 }, 2); - expected.delta.add(1, 'c', 3); - expected.delta.add(3, 'c', 1); + SECTION("symbols cnt == 1") { + nft = Nft(delta, { 0 }, { 2 }, { 0, 0, 0 }, 2); + nft.insert_identity(1, 'c'); - CHECK(are_equivalent(nft, expected)); + expected = Nft(delta, { 0 }, { 2 }, { 0, 0, 0, 1 }, 2); + expected.delta.add(1, 'c', 3); + expected.delta.add(3, 'c', 1); + + CHECK(are_equivalent(nft, expected)); + } + + SECTION("symbols cnt == 2") { + nft = Nft(delta, { 0 }, { 2 }, { 0, 0, 0 }, 2); + nft.insert_identity(1, {'c', 'd'}); + + expected = Nft(delta, { 0 }, { 2 }, { 0, 0, 0, 1 }, 2); + expected.insert_identity(1, 'c'); + expected.insert_identity(1, 'd'); + + CHECK(are_equivalent(nft, expected)); + } } SECTION("num_of_levels == 4") { - nft = Nft(delta, { 0 }, { 2 }, { 0, 0, 0 }, 4); - nft.insert_identity(1, 'c'); - expected = Nft(delta, { 0 }, { 2 }, { 0, 0, 0, 1, 2, 3 }, 4); - expected.delta.add(1, 'c', 3); - expected.delta.add(3, 'c', 4); - expected.delta.add(4, 'c', 5); - expected.delta.add(5, 'c', 1); + SECTION("symbols cnt == 1") { + nft = Nft(delta, { 0 }, { 2 }, { 0, 0, 0 }, 4); + nft.insert_identity(1, 'c'); - CHECK(are_equivalent(nft, expected)); + expected = Nft(delta, { 0 }, { 2 }, { 0, 0, 0, 1, 2, 3 }, 4); + expected.delta.add(1, 'c', 3); + expected.delta.add(3, 'c', 4); + expected.delta.add(4, 'c', 5); + expected.delta.add(5, 'c', 1); + + CHECK(are_equivalent(nft, expected)); + } + + SECTION("symbols cnt == 4") { + nft = Nft(delta, { 0 }, { 2 }, { 0, 0, 0 }, 4); + nft.insert_identity(1, {'c', 'd', 'e', 'f'}); + + expected = Nft(delta, { 0 }, { 2 }, { 0, 0, 0, 1, 2, 3 }, 4); + expected.insert_identity(1, 'c'); + expected.insert_identity(1, 'd'); + expected.insert_identity(1, 'e'); + expected.insert_identity(1, 'f'); + + CHECK(are_equivalent(nft, expected)); + + } } } From 381d3039187a189e454d21614a6719e086c531d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Tue, 5 Mar 2024 11:13:55 +0100 Subject: [PATCH 3/3] Use two overloaded functions instead of an optional parameter --- include/mata/nfa/nfa.hh | 19 ++++++++++--- include/mata/nft/nft.hh | 62 ++++++++++++++++++++++++++++++----------- src/nfa/nfa.cc | 32 +++++++++------------ src/nft/nft.cc | 53 ++++++++++++++++++++--------------- 4 files changed, 104 insertions(+), 62 deletions(-) diff --git a/include/mata/nfa/nfa.hh b/include/mata/nfa/nfa.hh index 69e070ba4..e3cabb2b1 100644 --- a/include/mata/nfa/nfa.hh +++ b/include/mata/nfa/nfa.hh @@ -104,14 +104,25 @@ public: State add_state(State state); /** - * Inserts a @p word into the NFA from a source state @p src to a target state @p tgt. + * Inserts a @p word into the NFA from a source state @p source to a target state @p target. * Creates new states along the path of the @p word. * - * @param src The source state where the word begins. It must already be a part of the automaton. + * @param source The source state where the word begins. It must already be a part of the automaton. * @param word The nonempty word to be inserted into the NFA. - * @param tgt The target state where the word ends. If set to Limits::max_state, the word ends in a new state. + * @param target The target state where the word ends. + * @return The state @p target where the inserted @p word ends. */ - State insert_word(const State src, const Word &word, const State tgt = Limits::max_state); + State insert_word(State source, const Word& word, State target); + + /** + * Inserts a @p word into the NFA from a source state @p source to a new target state. + * Creates new states along the path of the @p word. + * + * @param source The source state where the word begins. It must already be a part of the automaton. + * @param word The nonempty word to be inserted into the NFA. + * @return The newly created target state where the inserted @p word ends. + */ + State insert_word(State source, const Word& word); /** * @brief Get the current number of states in the whole automaton. diff --git a/include/mata/nft/nft.hh b/include/mata/nft/nft.hh index 44ab65cfc..d25e584bf 100644 --- a/include/mata/nft/nft.hh +++ b/include/mata/nft/nft.hh @@ -143,33 +143,63 @@ public: State add_state_with_level(State state, Level level); /** - * Inserts a @p word into the NFT from a source state @p src to a target state @p tgt. + * Inserts a @p word into the NFT from a source state @p source to a target state @p target. * Creates new states along the path of the @p word. * * If the length of @p word is less than @c num_of_levels, then the last symbol of @p word - * will form a transition going directly from the last inner state to @p tgt. The level - * of the state @p tgt must be 0 or greater than the level of the last inner state. + * will form a transition going directly from the last inner state to @p target. The level + * of the state @p target must be 0 or greater than the level of the last inner state. * - * @param src The source state where the word begins. It must already be a part of the transducer. + * @param source The source state where the word begins. It must already be a part of the transducer. * @param word The nonempty word to be inserted into the NFA. - * @param tgt The target state where the word ends. If set to Limits::max_state, the word ends in a new state. + * @param target The target state where the word ends. + * @return The state @p target where the inserted @p word ends. */ - State insert_word(const State src, const Word &word, const State tgt = Limits::max_state); + State insert_word(State source, const Word &word, State target); /** - * Inserts a word, which is created by interleaving parts from @p word_part_on_level, into the NFT - * from a source state @p src to a target state @p tgt, creating new states along its path. + * @brief Inserts a @p word into the NFT from a source state @p source to a newly created target state, creating + * new states along the path of the @p word. * - * The length of the inserted word equals @c num_of_levels * the maximum word length in the vector @p word_part_on_level. - * At least one Word in @p word_part_on_level must be nonempty. - * The vector @p word_part_on_level must have a size equal to @c num_of_levels. + * If the length of @p word is less than @c num_of_levels, then the last symbol of @p word + * will form a transition going directly from the last inner state to the newly created target. + * + * @param source The source state where the word begins. It must already be a part of the transducer. + * @param word The nonempty word to be inserted into the NFA. + * @return The newly created target where the inserted word ends. + */ + State insert_word(State source, const Word &word); + + /** + * @brief Inserts a word, which is created by interleaving parts from @p word_parts_on_levels, into the NFT + * from a source state @p source to a target state @p target, creating new states along the path of @p word. + * + * The length of the inserted word equals @c num_of_levels * the maximum word length in the vector @p word_parts_on_levels. + * At least one Word in @p word_parts_on_levels must be nonempty. + * The vector @p word_parts_on_levels must have a size equal to @c num_of_levels. + * Words shorter than the maximum word length are interpreted as words followed by a sequence of epsilons to match the maximum length. + * + * @param source The source state where the word begins. This state must already exist in the transducer and must be of a level 0. + * @param word_parts_on_levels The vector of word parts, with each part corresponding to a different level. + * @param target The target state where the word ends. + * @return The state @p target where the inserted @p word_parts_on_levels ends. + */ + State insert_word_by_parts(State source, const std::vector& word_parts_on_levels, State target); + + /** + * @brief Inserts a word, which is created by interleaving parts from @p word_parts_on_levels, into the NFT + * from a source state @p source to a target state @p target, creating new states along the path of @p word. + * + * The length of the inserted word equals @c num_of_levels * the maximum word length in the vector @p word_parts_on_levels. + * At least one Word in @p word_parts_on_levels must be nonempty. + * The vector @p word_parts_on_levels must have a size equal to @c num_of_levels. * Words shorter than the maximum word length are interpreted as words followed by a sequence of epsilons to match the maximum length. * - * @param src The source state where the word begins. This state must already exist in the transducer and must be of a level 0. - * @param word_part_on_level The vector of word parts, with each part corresponding to a different level. - * @param tgt The target state where the word ends. If set to Limits::max_state, the word ends in a new state. + * @param source The source state where the word begins. This state must already exist in the transducer and must be of a level 0. + * @param word_parts_on_levels The vector of word parts, with each part corresponding to a different level. + * @return The newly created target where the inserted @p word_parts_on_levels ends. */ - State insert_word_by_parts(const State src, const std::vector &word_part_on_level, const State tgt = Limits::max_state); + State insert_word_by_parts(State source, const std::vector& word_parts_on_levels); /** * Inserts identity transitions into the NFT. @@ -177,7 +207,7 @@ public: * @param state The state where the identity transition will be inserted. This serves as both the source and target state. * @param symbol The vector of symbols used for the identity transition. Identity will be created for each symbol in the vector. */ - void insert_identity(const State state, const std::vector &symbols); + void insert_identity(State state, const std::vector& symbols); /** * Inserts an identity transition into the NFT. diff --git a/src/nfa/nfa.cc b/src/nfa/nfa.cc index 927a9d4f5..2e4956ef8 100644 --- a/src/nfa/nfa.cc +++ b/src/nfa/nfa.cc @@ -544,24 +544,21 @@ State Nfa::add_state(State state) { return state; } -State Nfa::insert_word(const State src, const Word &word, const State tgt) { +State Nfa::insert_word(const State source, const Word &word, const State target) { assert(!word.empty()); - assert(src < num_of_states()); + const size_t num_of_states_orig{ num_of_states() }; + assert(source < num_of_states_orig); + assert(target < num_of_states_orig); const size_t word_len = word.size(); if (word_len == 1) { - if (tgt == Limits::max_state) { - State new_tgt = add_state(); - delta.add(src, word[0], new_tgt); - return new_tgt; - } - delta.add(src, word[0], tgt); - return tgt; + delta.add(source, word[0], target); + return target; } - // Add transition src --> inner_state. + // Add transition source --> inner_state. State inner_state = add_state(); - delta.add(src, word[0], inner_state); + delta.add(source, word[0], inner_state); // Add transitions inner_state --> inner_state State prev_state = inner_state; @@ -571,16 +568,13 @@ State Nfa::insert_word(const State src, const Word &word, const State tgt) { prev_state = inner_state; } - // Add transition inner_state --> tgt - if (tgt == Limits::max_state) { - State new_tgt = add_state(); - delta.add(prev_state, word[word_len - 1], new_tgt); - return new_tgt; - } - delta.add(prev_state, word[word_len - 1], tgt); - return tgt; + // Add transition inner_state --> target + delta.add(prev_state, word[word_len - 1], target); + return target; } +State Nfa::insert_word(const State source, const Word &word) { return insert_word(source, word, add_state()); } + size_t Nfa::num_of_states() const { return std::max({ static_cast(initial.domain_size()), diff --git a/src/nft/nft.cc b/src/nft/nft.cc index a52175038..5e5eb5adc 100644 --- a/src/nft/nft.cc +++ b/src/nft/nft.cc @@ -305,13 +305,16 @@ State Nft::add_state_with_level(const State state, const Level level) { return Nfa::add_state(state); } -State Nft::insert_word(const State src, const Word &word, const State tgt) { +State Nft::insert_word(const State source, const Word &word, const State target) { assert(0 < num_of_levels); + const size_t num_of_states_orig{ num_of_states() }; + assert(source < num_of_states_orig); + assert(target < num_of_states_orig); - const State first_new_state = num_of_states(); - const State word_tgt = Nfa::insert_word(src, word, tgt); + const State first_new_state = num_of_states_orig; + const State word_tgt = Nfa::insert_word(source, word, target); const size_t num_of_states_after = num_of_states(); - const Level src_lvl = levels[src]; + const Level src_lvl = levels[source]; Level lvl = (num_of_levels == 1 ) ? src_lvl : (src_lvl + 1); State state{ first_new_state }; @@ -324,19 +327,24 @@ State Nft::insert_word(const State src, const Word &word, const State tgt) { return word_tgt; } -State Nft::insert_word_by_parts(const State src, const std::vector &word_part_on_level, const State tgt) { +State Nft::insert_word(const State source, const Word &word) { return insert_word(source, word, add_state()); } + +State Nft::insert_word_by_parts(const State source, const std::vector &word_parts_on_levels, const State target) { assert(0 < num_of_levels); - assert(word_part_on_level.size() == num_of_levels); - assert(src < num_of_states()); - assert(levels[src] == 0); + assert(word_parts_on_levels.size() == num_of_levels); + const size_t num_of_states_orig{ num_of_states() }; + assert(source < num_of_states_orig); + assert(target < num_of_states_orig); + assert(levels[source] == 0); + assert(levels[target] == 0); if (num_of_levels == 1) { - return Nft::insert_word(src, word_part_on_level[0], tgt); + return Nft::insert_word(source, word_parts_on_levels[0], target); } size_t max_word_part_len = std::max_element( - word_part_on_level.begin(), - word_part_on_level.end(), + word_parts_on_levels.begin(), + word_parts_on_levels.end(), [](const Word& a, const Word& b) { return a.size() < b.size(); } )->size(); assert(0 < max_word_part_len); @@ -344,22 +352,22 @@ State Nft::insert_word_by_parts(const State src, const std::vector &word_p std::vector word_part_it_v(num_of_levels); for (Level lvl{ 0 }; lvl < num_of_levels; lvl++) { - word_part_it_v[lvl] = word_part_on_level[lvl].begin(); + word_part_it_v[lvl] = word_parts_on_levels[lvl].begin(); } // This function retrieves the next symbol from a word part at a specified level and advances the corresponding iterator. // Returns EPSILON when the iterator reaches the end of the word part. auto get_next_symbol = [&](Level lvl) { - if (word_part_it_v[lvl] == word_part_on_level[lvl].end()) { + if (word_part_it_v[lvl] == word_parts_on_levels[lvl].end()) { return EPSILON; } return *(word_part_it_v[lvl]++); }; - // Add transition src --> inner_state. + // Add transition source --> inner_state. Level inner_lvl = (num_of_levels == 1 ) ? 0 : 1; State inner_state = add_state_with_level(inner_lvl); - delta.add(src, get_next_symbol(0), inner_state); + delta.add(source, get_next_symbol(0), inner_state); // Add transition inner_state --> inner_state State prev_state = inner_state; @@ -372,14 +380,13 @@ State Nft::insert_word_by_parts(const State src, const std::vector &word_p prev_lvl = inner_lvl; } - // Add transition inner_state --> tgt. - if (tgt == Limits::max_state) { - State new_tgt = add_state_with_level(0); - delta.add(prev_state, get_next_symbol(prev_lvl), new_tgt); - return new_tgt; - } - delta.add(prev_state, get_next_symbol(prev_lvl), tgt); - return tgt; + // Add transition inner_state --> target. + delta.add(prev_state, get_next_symbol(prev_lvl), target); + return target; +} + +State Nft::insert_word_by_parts(const State source, const std::vector &word_parts_on_levels) { + return insert_word_by_parts(source, word_parts_on_levels, add_state()); } void Nft::insert_identity(const State state, const std::vector &symbols) {