From 13a53699098d5687e306c51f1e849d1eb21fd16f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Tr=C3=A1vn=C3=AD=C4=8Dek?= <jan.travnicek@fit.cvut.cz>
Date: Sat, 5 Mar 2022 20:16:59 +0100
Subject: [PATCH] algo: introduces ranked alphabet generator and addapts tree
 automaton generator

---
 .../alphabet/generate/AsRankedAlphabet.cpp    | 28 ++++++++
 .../src/alphabet/generate/AsRankedAlphabet.h  | 72 +++++++++++++++++++
 .../generate/RandomTreeAutomatonFactory.cpp   | 49 -------------
 .../generate/RandomTreeAutomatonFactory.h     | 15 ----
 tests/cppaql/conversionsTest2.cpp             |  2 +-
 5 files changed, 101 insertions(+), 65 deletions(-)
 create mode 100644 alib2algo/src/alphabet/generate/AsRankedAlphabet.cpp
 create mode 100644 alib2algo/src/alphabet/generate/AsRankedAlphabet.h

diff --git a/alib2algo/src/alphabet/generate/AsRankedAlphabet.cpp b/alib2algo/src/alphabet/generate/AsRankedAlphabet.cpp
new file mode 100644
index 0000000000..e4413580dd
--- /dev/null
+++ b/alib2algo/src/alphabet/generate/AsRankedAlphabet.cpp
@@ -0,0 +1,28 @@
+#include "AsRankedAlphabet.h"
+
+#include <registration/AlgoRegistration.hpp>
+
+namespace {
+
+auto AsRankedAlphabet = registration::AbstractRegister < alphabet::generate::AsFullRankedAlphabet, ext::set < common::ranked_symbol < object::Object > >, const ext::set < object::Object > &, size_t > ( alphabet::generate::AsFullRankedAlphabet::asRankedAlphabet < object::Object >, "alphabet", "maxRank" ).setDocumentation (
+"Generates ranked alphabet from unranked alphabet so that all symbols are put into the result with all ranks.\n\
+\n\
+@param alphabet the converted alphabet\n\
+@param maxRank the maximal rank used\n\
+@return the generated ranked alphabet" );
+
+auto AsRandomRankedAlphabet = registration::AbstractRegister < alphabet::generate::AsRandomRankedAlphabet, ext::set < common::ranked_symbol < object::Object > >, const ext::set < object::Object > &, size_t > ( alphabet::generate::AsRandomRankedAlphabet::asRankedAlphabet < object::Object >, "alphabet", "maxRank" ).setDocumentation (
+"Generates ranked alphabet from unranked alphabet so that at least one symbol is assigned rank 0 and other are random.\n\
+\n\
+@param alphabet the converted alphabet\n\
+@param maxRank the maximal rank used\n\
+@return the generated ranked alphabet" );
+
+auto AsSequencedRankedAlphabet = registration::AbstractRegister < alphabet::generate::AsSequencedRankedAlphabet, ext::set < common::ranked_symbol < object::Object > >, const ext::set < object::Object > &, size_t > ( alphabet::generate::AsSequencedRankedAlphabet::asRankedAlphabet < object::Object >, "alphabet", "maxRank" ).setDocumentation (
+"Generates ranked alphabet from unranked alphabet so that first symbol is assigned rank 0, second rank 1 up to maxRank-th symbol rank maxRank when the assigned ranks assigned also reset to 0 and are increases again.\n\
+\n\
+@param alphabet the converted alphabet\n\
+@param maxRank the maximal rank used\n\
+@return the generated ranked alphabet" );
+
+} /* namespace */
diff --git a/alib2algo/src/alphabet/generate/AsRankedAlphabet.h b/alib2algo/src/alphabet/generate/AsRankedAlphabet.h
new file mode 100644
index 0000000000..a097462a99
--- /dev/null
+++ b/alib2algo/src/alphabet/generate/AsRankedAlphabet.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <ext/random>
+
+#include <alib/set>
+
+#include <common/ranked_symbol.hpp>
+
+namespace alphabet::generate {
+
+class AsFullRankedAlphabet {
+public:
+template < class T >
+static ext::set < common::ranked_symbol < T > > asRankedAlphabet ( const ext::set < T > & alphabet, size_t maxRank ) {
+	ext::set < common::ranked_symbol < T > > res;
+
+	if ( alphabet.size ( ) == 0 )
+		throw std::invalid_argument ( "There needs to be at least one symbol for nullary symbol." );
+
+	for ( size_t i = 0; i <= maxRank; ++ i ) {
+		for ( const T & symbol : alphabet ) {
+			res.insert ( common::ranked_symbol < T > ( symbol, i ) );
+		}
+	}
+	return res;
+}
+
+};
+
+class AsRandomRankedAlphabet {
+public:
+template < class T >
+static ext::set < common::ranked_symbol < T > > asRankedAlphabet ( const ext::set < T > & alphabet, size_t maxRank ) {
+	ext::set < common::ranked_symbol < T > > res;
+
+	if ( alphabet.size ( ) == 0 )
+		throw std::invalid_argument ( "There needs to be at least one symbol for nullary symbol." );
+
+	size_t nullaryIndex = static_cast < size_t > ( ext::random_devices::semirandom ( ) % ( alphabet.size ( ) ) );
+
+	for ( auto iter = alphabet.begin ( ); iter != alphabet.end ( ); ++ iter ) {
+		if ( res.size ( ) == nullaryIndex )
+			res.insert ( common::ranked_symbol < T > ( * iter, 0 ) );
+		else
+			res.insert ( common::ranked_symbol < T > ( * iter, static_cast < size_t > ( ext::random_devices::semirandom ( ) % ( maxRank + 1 ) ) ) );
+	}
+
+	return res;
+}
+
+};
+
+class AsSequencedRankedAlphabet {
+public:
+template < class T >
+static ext::set < common::ranked_symbol < T > > asRankedAlphabet ( const ext::set < T > & alphabet, size_t maxRank ) {
+	ext::set < common::ranked_symbol < T > > res;
+
+	if ( alphabet.size ( ) <= maxRank )
+		throw std::invalid_argument ( "Not enough symbols were provided to fulfill the max rank request." );
+
+	auto iter = alphabet.begin ( );
+	for ( size_t i = 0; iter != alphabet.end ( ); i = ( i + 1 ) % ( maxRank + 1 ) ) {
+		res.insert ( common::ranked_symbol < T > ( * iter ++, i ) );
+	}
+
+	return res;
+}
+
+};
+
+} /* namespace alphabet::generate */
diff --git a/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.cpp b/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.cpp
index 38f56b280b..5013bbfd3f 100644
--- a/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.cpp
+++ b/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.cpp
@@ -3,45 +3,6 @@
 
 namespace automaton::generate {
 
-namespace {
-	constexpr unsigned ENGLISH_ALPHABET_SIZE = 26;
-}
-
-automaton::NFTA < std::string, unsigned > RandomTreeAutomatonFactory::generateNFTA( size_t statesCount, size_t alphabetSize, size_t maxRank, bool randomizedAlphabet, double density ) {
-	if ( alphabetSize > ENGLISH_ALPHABET_SIZE )
-		throw exception::CommonException("Too big alphabet.");
-
-	if(alphabetSize < 1)
-		throw exception::CommonException("Too small alphabet.");
-
-	ext::deque < std::string > alphabet;
-	for(char i = 'a'; i <= 'z'; i++)
-		alphabet.push_back ( std::string ( 1, i ) );
-
-	if(randomizedAlphabet)
-		shuffle(alphabet.begin(), alphabet.end(), ext::random_devices::semirandom);
-
-	alphabet.resize ( alphabetSize );
-
-	ext::deque < common::ranked_symbol < std::string > > rankedAlphabet;
-
-	for ( std::string && symbol : ext::make_mover ( alphabet ) ) {
-		rankedAlphabet.push_back ( common::ranked_symbol < std::string > ( std::move ( symbol ), ext::random_devices::semirandom() % ( maxRank + 1 ) ) );
-	}
-
-	bool containsNullary = false;
-	for ( common::ranked_symbol < std::string > & rankedSymbol : rankedAlphabet ) {
-		containsNullary |= rankedSymbol.getRank ( ) == 0;
-	}
-
-	if ( ! containsNullary ) {
-		int c = ext::random_devices::semirandom() % rankedAlphabet.size ( );
-		rankedAlphabet [ c ] = common::ranked_symbol ( rankedAlphabet [ c ].getSymbol ( ), 0u );
-	}
-
-	return automaton::generate::RandomTreeAutomatonFactory::LeslieConnectedNFTA( statesCount, rankedAlphabet, density );
-}
-
 unsigned RandomTreeAutomatonFactory::ithAccessibleState ( const ext::deque < bool > & VStates, size_t i ) {
 	i ++;
 	for( size_t j = 0; j < VStates.size ( ); j++ ) {
@@ -77,14 +38,4 @@ auto GenerateNFTA1 = registration::AbstractRegister < automaton::generate::Rando
 @param density density of the transition function\n\
 @return random nondeterministic finite automaton" );
 
-auto GenerateNFTA2 = registration::AbstractRegister < automaton::generate::RandomTreeAutomatonFactory, automaton::NFTA < std::string, unsigned >, size_t, size_t, size_t, bool, double > ( automaton::generate::RandomTreeAutomatonFactory::generateNFTA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesCount", "alphabetSize", "maxRank", "randomizedAlphabet", "density" ).setDocumentation (
-"Generates a random finite automaton.\n\
-\n\
-@param statesCount number of states in the generated automaton\n\
-@param alphabetSize size of the alphabet (1-26)\n\
-@param maxRank the maximum rank in the randomly generated alphabet\n\
-@param randomizedAlphabet selects random symbols from a-z range if true\n\
-@param density density of the transition function (0-100). 100 means every possible transition is created\n\
-@return random nondeterministic finite automaton" );
-
 } /* namespace */
diff --git a/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.h b/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.h
index de5b907d57..d58ac16660 100644
--- a/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.h
+++ b/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.h
@@ -54,21 +54,6 @@ public:
 	template < class SymbolType >
 	static automaton::NFTA < SymbolType, unsigned > generateNFTA ( size_t statesCount, const ext::set < common::ranked_symbol < SymbolType > > & alphabet, double density );
 
-	/**
-	 * \overload
-	 *
-	 * Generates a random finite automaton.
-	 *
-	 * \param statesCount number of states in the generated automaton
-	 * \param alphabetSize size of the alphabet (1-26)
-	 * \param maxRank the maximum rank in the randomly generated alphabet
-	 * \param randomizedAlphabet selects random symbols from a-z range if true
-	 * \param density density of the transition function (0-100). 100 means every possible transition is created
-	 *
-	 * \return random nondeterministic finite automaton
-	 */
-	static automaton::NFTA < std::string, unsigned > generateNFTA ( size_t statesCount, size_t alphabetSize, size_t maxRank, bool randomizedAlphabet, double density );
-
 private:
 	/**
 	 * Selects ith accessible state form \p VStates.
diff --git a/tests/cppaql/conversionsTest2.cpp b/tests/cppaql/conversionsTest2.cpp
index 4d0c0c0ed1..b61bad0456 100644
--- a/tests/cppaql/conversionsTest2.cpp
+++ b/tests/cppaql/conversionsTest2.cpp
@@ -12,7 +12,7 @@ const double RAND_DENSITY = 5;
 const size_t ITERATIONS = 50;
 
 std::string qGenNFTA ( ) {
-    return ext::concat ( "execute automaton::generate::RandomTreeAutomatonFactory (size_t)", rand ( ) % RAND_STATES + 1, " (size_t)", rand ( ) % RAND_ALPHABET + 1, " (size_t)", rand ( ) % RAND_RANK, " (bool)true (double)\"", RAND_DENSITY, "\"" );
+    return ext::concat ( "execute automaton::generate::RandomTreeAutomatonFactory (size_t)", rand ( ) % RAND_STATES + 1, " <(alphabet::generate::AsFullRankedAlphabet <(alphabet::generate::GenerateAlphabet (size_t)", rand ( ) % RAND_ALPHABET + 1, " true true)" " (size_t)", rand ( ) % RAND_RANK, ") (double)\"", RAND_DENSITY, "\"" );
 }
 
 TEST_CASE ( "FTA-RTE conversions test", "[integration]" ) {
-- 
GitLab