From de75b2c02201e3cb7f094c4e6d375c8fd013e1c5 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Tue, 25 Sep 2018 07:35:47 +0200 Subject: [PATCH] template random automaton and grammar factory --- .../generate/RandomAutomatonFactory.cpp | 144 +++------------- .../generate/RandomAutomatonFactory.h | 163 ++++++++++++++++-- .../grammar/generate/RandomGrammarFactory.cpp | 68 ++------ .../grammar/generate/RandomGrammarFactory.h | 56 +++++- alib2algo/test-src/playTest.cpp | 2 +- alib2algo/test-src/playTest.h | 2 +- tests.anormalize.sh | 2 +- 7 files changed, 237 insertions(+), 200 deletions(-) diff --git a/alib2algo/src/automaton/generate/RandomAutomatonFactory.cpp b/alib2algo/src/automaton/generate/RandomAutomatonFactory.cpp index deaedc923d..a5288b451e 100644 --- a/alib2algo/src/automaton/generate/RandomAutomatonFactory.cpp +++ b/alib2algo/src/automaton/generate/RandomAutomatonFactory.cpp @@ -6,151 +6,53 @@ */ #include "RandomAutomatonFactory.h" -#include <exception/CommonException.h> - -#include <alib/algorithm> -#include <alib/random> - #include <registration/AlgoRegistration.hpp> namespace automaton { namespace generate { -automaton::NFA < > RandomAutomatonFactory::generateNFA( size_t statesCount, const ext::set<DefaultSymbolType> & alphabet, double density ) { - ext::deque<DefaultSymbolType> alphabet2 ( alphabet.begin ( ), alphabet.end ( ) ); - return RandomAutomatonFactory::LeslieConnectedNFA( statesCount, alphabet2, density ); -} - -automaton::NFA < > RandomAutomatonFactory::generateNFA( size_t statesCount, size_t alphabetSize, bool randomizedAlphabet, double density ) { +automaton::NFA < char, unsigned > RandomAutomatonFactory::generateNFA( size_t statesCount, size_t alphabetSize, bool randomizedAlphabet, double density ) { if(alphabetSize > 26) throw exception::CommonException("Too big alphabet."); - ext::vector<DefaultSymbolType> symbols; + ext::deque < char > alphabet; for(int i = 0; i < 26; i++) - symbols.push_back(DefaultSymbolType((char)(i + 'a'))); + alphabet.push_back ( i + 'a' ); if(randomizedAlphabet) - shuffle(symbols.begin(), symbols.end(), ext::random_devices::semirandom); + shuffle(alphabet.begin(), alphabet.end(), ext::random_devices::semirandom); - ext::deque<DefaultSymbolType> alphabet(symbols.begin(), symbols.begin() + alphabetSize); + alphabet.resize ( alphabetSize ); return RandomAutomatonFactory::LeslieConnectedNFA( statesCount, alphabet, density ); } -automaton::NFA < > RandomAutomatonFactory::LeslieConnectedNFA( size_t n, const ext::deque<DefaultSymbolType> & alphabet, double density ) { - if( alphabet.size( ) <= 0 ) - throw exception::CommonException( "Alphabet size must be greater than 0." ); - - ext::deque<bool> VStates; - ext::deque<DefaultStateType> Q; - int unvisited; - - automaton::NFA < > automaton( DefaultStateType( 0 ) ); - - for( const auto & s : alphabet ) - automaton.addInputSymbol( s ); - - for( size_t i = 0; i < n; i ++ ) { - VStates.push_back( false ); - Q.push_back( DefaultStateType ( (int) i ) ); - automaton.addState( Q[ i ] ); - } - - if( n == 0 ) { - return automaton; - } else if( n == 1 ) { - automaton.addTransition( Q[ 0 ], alphabet[ ext::random_devices::semirandom() % alphabet.size( ) ], Q[ 0 ] ); - - unvisited = 0; - VStates[ 0 ] = true; - } else { - int x = ( ext::random_devices::semirandom() % ( n - 1 ) ) + 1; - automaton.addTransition( Q[ 0 ], alphabet[ ext::random_devices::semirandom() % alphabet.size( ) ], Q[ x ] ); - unvisited = n - 2; - - VStates[ 0 ] = true; - VStates[ x ] = true; - } - - while( unvisited != 0 ) { - size_t y = ext::random_devices::semirandom() % ( n - unvisited ) + 1; // select y-th accessible state - size_t z = ext::random_devices::semirandom() % unvisited + 1; // select z-th inaccessible state - int a = -1, b = -1; +unsigned RandomAutomatonFactory::ithAccessibleState ( const ext::deque < bool > & VStates, size_t i ) { + i ++; + for( size_t j = 0; j < VStates.size ( ); j++ ) { + if( VStates[ j ] == true ) + i --; - for( size_t i = 0, cnt = 0; i < n; i++ ) { - if( VStates[ i ] == true ) - cnt ++; - - if( cnt == y ) { - a = i; - break; - } - } - for( size_t i = 0, cnt = 0; i < n; i++ ) { - if( VStates[ i ] == false ) - cnt ++; - - if( cnt == z ) - { - b = i; - break; - } - } - - int c = ext::random_devices::semirandom() % alphabet.size( ); - automaton.addTransition( Q[ a ], alphabet[ c ], Q[ b ] ); - - - unvisited -= 1; - VStates[ b ] = true; - - // --------- - } - - for( const DefaultStateType & q : Q ) { - if( automaton.getTransitionsFromState( q ).size( ) == 0 && ext::random_devices::semirandom() % 100 < 90 ) - automaton.addFinalState( q ); - else if( automaton.getTransitionsFromState( q ).size( ) > 0 && ext::random_devices::semirandom() % 100 < 10 ) - automaton.addFinalState( q ); - } - - if( automaton.getFinalStates( ).size( ) == 0 ) { - if( n == 1 ) { - automaton.addFinalState( automaton.getInitialState( ) ); - } else { - for( const DefaultStateType & q : Q ) { - if( automaton.getTransitionsFromState( q ).size( ) == 0 ) { - automaton.addFinalState( q ); - break; - } - } - } + if( i == 0 ) + return i; } + throw std::logic_error ( "Not enough states in deque of visited states" ); +} - double mnn100 = 100.0 / alphabet.size( ) / n / n; - while( automaton.transitionsSize( ) * mnn100 < density ) { - int y = ext::random_devices::semirandom() % n; - int z = ext::random_devices::semirandom() % n; - int a = ext::random_devices::semirandom() % alphabet.size(); +unsigned RandomAutomatonFactory::ithInaccessibleState ( const ext::deque < bool > & VStates, size_t i ) { + i ++; + for( size_t j = 0; j < VStates.size ( ); j++ ) { + if( VStates[ j ] == false ) + i --; - automaton.addTransition( Q[ y ], alphabet [ a ], Q[ z ] ); + if( i == 0 ) + return j; } - - ext::map<DefaultSymbolType, bool> alphabetUsage; - for( const auto & a : automaton.getInputAlphabet( ) ) - alphabetUsage[ a ] = false; - for( const auto & t : automaton.getTransitions( ) ) - alphabetUsage[ t.first.second ] = true; - - for( const auto & kv : alphabetUsage ) - if( kv.second == false ) - automaton.removeInputSymbol( kv.first ); - - return automaton; + throw std::logic_error ( "Not enough states in deque of visited states" ); } -auto GenerateNFA = registration::AbstractRegister < RandomAutomatonFactory, automaton::NFA < >, size_t, size_t, bool, double > ( RandomAutomatonFactory::generateNFA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesCount", "alphabetSize", "randomizedAlphabet", "density" ); +auto GenerateNFA = registration::AbstractRegister < RandomAutomatonFactory, automaton::NFA < char, unsigned >, size_t, size_t, bool, double > ( RandomAutomatonFactory::generateNFA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesCount", "alphabetSize", "randomizedAlphabet", "density" ); } /* namespace generate */ diff --git a/alib2algo/src/automaton/generate/RandomAutomatonFactory.h b/alib2algo/src/automaton/generate/RandomAutomatonFactory.h index 38a0427f2e..b377e3a2c8 100644 --- a/alib2algo/src/automaton/generate/RandomAutomatonFactory.h +++ b/alib2algo/src/automaton/generate/RandomAutomatonFactory.h @@ -26,6 +26,10 @@ #include <alib/deque> #include <alib/set> +#include <alib/algorithm> +#include <alib/random> + +#include <exception/CommonException.h> #include <automaton/FSM/NFA.h> @@ -36,42 +40,169 @@ namespace generate { /** * Generator of random automata. * - * @details + * \details * The underlying generation algorithm is from Leslie, T: Efficient Approaches to Subset Construction, 1995. */ class RandomAutomatonFactory { public: /** * Generates a random finite automaton. - * @param statesCount number of states in the generated automaton - * @param alphabet Input alphabet of the automaton - * @param density density of the transition function - * @return random nondeterministic finite automaton + * \tparam SymbolType the type of terminal symbols of the random automaton + * + * \param statesCount number of states in the generated automaton + * \param alphabet Input alphabet of the automaton + * \param density density of the transition function + * + * \return random nondeterministic finite automaton */ - static automaton::NFA < > generateNFA( size_t statesCount, const ext::set<DefaultSymbolType> & alphabet, double density ); + template < class SymbolType > + static automaton::NFA < SymbolType, unsigned > generateNFA ( size_t statesCount, const ext::set < 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 randomizedAlphabet selects random symbols from a-z range if true - * @param density density of the transition function (0-1). 1 means every possible transition is created - * @return random nondeterministic finite automaton + * + * \param statesCount number of states in the generated automaton + * \param alphabetSize size of the alphabet (1-26) + * \param randomizedAlphabet selects random symbols from a-z range if true + * \param density density of the transition function (0-1). 1 means every possible transition is created + * + * \return random nondeterministic finite automaton */ - static automaton::NFA < > generateNFA( size_t statesCount, size_t alphabetSize, bool randomizedAlphabet, double density ); + static automaton::NFA < char, unsigned > generateNFA ( size_t statesCount, size_t alphabetSize, bool randomizedAlphabet, double density ); private: + /** + * Selects ith accessible state form \p VStates. + * + * \param VStates the states to select from + * \param i the specification which accessble state to select + * + * \return ith accessible state based on VStates + */ + static unsigned ithAccessibleState ( const ext::deque < bool > & VStates, size_t i ); + + /** + * Selects ith inaccessible state form \p VStates. + * + * \param VStates the states to select from + * \param i the specification which inaccessble state to select + * + * \return ith inaccessible state based on VStates + */ + static unsigned ithInaccessibleState ( const ext::deque < bool > & VStates, size_t i ); + /** * Leslie's connected NFA algorithm - * @param n number of states - * @param alphabet input alphabet - * @param density density of the transition function (0-1). 1 means every possible transition is created + * + * \tparam SymbolType the type of terminal symbols of the random automaton + * + * \param n number of states + * \param alphabet input alphabet + * \param density density of the transition function (0-1). 1 means every possible transition is created + * + * \return the actual random nondeterministic automaton */ - static automaton::NFA < > LeslieConnectedNFA( size_t n, const ext::deque<DefaultSymbolType> & alphabet, double density ); + template < class SymbolType > + static automaton::NFA < SymbolType, unsigned > LeslieConnectedNFA ( size_t n, const ext::deque < SymbolType > & alphabet, double density ); }; +template < class SymbolType > +automaton::NFA < SymbolType, unsigned > RandomAutomatonFactory::generateNFA ( size_t statesCount, const ext::set < SymbolType > & alphabet, double density ) { + ext::deque < SymbolType > alphabet2 ( alphabet.begin ( ), alphabet.end ( ) ); + return RandomAutomatonFactory::LeslieConnectedNFA ( statesCount, alphabet2, density ); +} + +template < class SymbolType > +automaton::NFA < SymbolType, unsigned > RandomAutomatonFactory::LeslieConnectedNFA ( size_t n, const ext::deque < SymbolType > & alphabet, double density ) { + if( alphabet.size( ) <= 0 ) + throw exception::CommonException( "Alphabet size must be greater than 0." ); + + ext::deque<bool> VStates; + ext::deque<unsigned> Q; + int unvisited; + + automaton::NFA < SymbolType, unsigned > automaton( 0 ); + + for( const auto & s : alphabet ) + automaton.addInputSymbol( s ); + + for( size_t i = 0; i < n; i ++ ) { + VStates.push_back( false ); + Q.push_back( i ); + automaton.addState( Q[ i ] ); + } + + if( n == 0 ) { + return automaton; + } else if( n == 1 ) { + automaton.addTransition( Q[ 0 ], alphabet[ ext::random_devices::semirandom() % alphabet.size( ) ], Q[ 0 ] ); + + unvisited = 0; + VStates[ 0 ] = true; + } else { + unsigned x = ( ext::random_devices::semirandom() % ( n - 1 ) ) + 1; + automaton.addTransition( Q[ 0 ], alphabet[ ext::random_devices::semirandom() % alphabet.size( ) ], Q[ x ] ); + unvisited = n - 2; + + VStates[ 0 ] = true; + VStates[ x ] = true; + } + + while( unvisited != 0 ) { + size_t a = ithAccessibleState ( VStates, ext::random_devices::semirandom() % ( n - unvisited ) ); // select y-th accessible state + size_t b = ithInaccessibleState ( VStates, ext::random_devices::semirandom() % unvisited ); // select z-th inaccessible state + + int c = ext::random_devices::semirandom() % alphabet.size( ); + automaton.addTransition( Q[ a ], alphabet[ c ], Q[ b ] ); + + unvisited -= 1; + VStates[ b ] = true; + } + + for( const unsigned & q : Q ) { + if( automaton.getTransitionsFromState( q ).size( ) == 0 && ext::random_devices::semirandom() % 100 < 90 ) + automaton.addFinalState( q ); + else if( automaton.getTransitionsFromState( q ).size( ) > 0 && ext::random_devices::semirandom() % 100 < 10 ) + automaton.addFinalState( q ); + } + + if( automaton.getFinalStates( ).size( ) == 0 ) { + if( n == 1 ) { + automaton.addFinalState( automaton.getInitialState( ) ); + } else { + for( const unsigned & q : Q ) { + if( automaton.getTransitionsFromState( q ).size( ) == 0 ) { + automaton.addFinalState( q ); + break; + } + } + } + } + + double mnn100 = 100.0 / alphabet.size( ) / n / n; + while( automaton.transitionsSize( ) * mnn100 < density ) { + int y = ext::random_devices::semirandom() % n; + int z = ext::random_devices::semirandom() % n; + int a = ext::random_devices::semirandom() % alphabet.size(); + + automaton.addTransition( Q[ y ], alphabet [ a ], Q[ z ] ); + } + + ext::map<SymbolType, bool> alphabetUsage; + for( const auto & a : automaton.getInputAlphabet( ) ) + alphabetUsage[ a ] = false; + for( const auto & t : automaton.getTransitions( ) ) + alphabetUsage[ t.first.second ] = true; + + for( const auto & kv : alphabetUsage ) + if( kv.second == false ) + automaton.removeInputSymbol( kv.first ); + + return automaton; +} + } /* namespace generate */ } /* namespace automaton */ diff --git a/alib2algo/src/grammar/generate/RandomGrammarFactory.cpp b/alib2algo/src/grammar/generate/RandomGrammarFactory.cpp index f612148ac4..9c74a5eeea 100644 --- a/alib2algo/src/grammar/generate/RandomGrammarFactory.cpp +++ b/alib2algo/src/grammar/generate/RandomGrammarFactory.cpp @@ -6,81 +6,35 @@ */ #include "RandomGrammarFactory.h" -#include <exception/CommonException.h> - -#include <alib/algorithm> -#include <alib/random> #include <registration/AlgoRegistration.hpp> namespace grammar { namespace generate { -grammar::CFG < > RandomGrammarFactory::generateCFG( ext::set<DefaultSymbolType> nonterminals, ext::set<DefaultSymbolType> terminals, double density ) { - ext::deque<DefaultSymbolType> terminals2(terminals.begin(), terminals.end()); - ext::deque<DefaultSymbolType> nonterminals2(nonterminals.begin(), nonterminals.end()); - return RandomGrammarFactory::randomCFG( nonterminals2, terminals2, density ); -} - auto GenerateCFG1 = registration::AbstractRegister < RandomGrammarFactory, grammar::CFG < >, ext::set < DefaultSymbolType >, ext::set < DefaultSymbolType >, double > ( RandomGrammarFactory::generateCFG, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "nonterminals", "terminals", "density" ); -grammar::CFG < > RandomGrammarFactory::generateCFG( size_t nonterminalsCount, size_t terminalsCount, bool randomizedAlphabet, double density ) { +grammar::CFG < char, char > RandomGrammarFactory::generateCFG ( size_t nonterminalsCount, size_t terminalsCount, bool randomizedAlphabet, double density ) { if(terminalsCount > 26) throw exception::CommonException("Too big terminals count."); - ext::vector<DefaultSymbolType> symbols; - for(int i = 0; i < 26; i++) symbols.push_back(DefaultSymbolType((char)(i + 'a'))); - if(randomizedAlphabet) shuffle(symbols.begin(), symbols.end(), ext::random_devices::semirandom); - ext::deque<DefaultSymbolType> terminals(symbols.begin(), symbols.begin() + terminalsCount); + ext::deque < char > terminals; + for(int i = 0; i < 26; i++) terminals.push_back ( i + 'a' ); + if(randomizedAlphabet) shuffle ( terminals.begin ( ), terminals.end ( ), ext::random_devices::semirandom ); + terminals.resize ( terminalsCount ); if(nonterminalsCount > 26) throw exception::CommonException("Too big nonterminals count."); - ext::vector<DefaultSymbolType> symbols2; - for(int i = 0; i < 26; i++) symbols2.push_back(DefaultSymbolType((char)(i + 'A'))); - if(randomizedAlphabet) shuffle(symbols2.begin(), symbols2.end(), ext::random_devices::semirandom); - ext::deque<DefaultSymbolType> nonterminals(symbols2.begin(), symbols2.begin() + nonterminalsCount); + ext::deque < char > nonterminals; + for(int i = 0; i < 26; i++) nonterminals.push_back ( i + 'A' ); + if ( randomizedAlphabet ) shuffle ( nonterminals.begin ( ), nonterminals.end ( ), ext::random_devices::semirandom ); + nonterminals.resize ( nonterminalsCount); - return RandomGrammarFactory::randomCFG( nonterminals, terminals, density ); + return RandomGrammarFactory::randomCFG ( nonterminals, terminals, density ); } -auto GenerateCFG2 = registration::AbstractRegister < RandomGrammarFactory, grammar::CFG < >, size_t, size_t, bool, double> ( RandomGrammarFactory::generateCFG, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "nonterminalsCount", "terminalsCount", "randomizedAlphabet", "density" ); - -grammar::CFG < > RandomGrammarFactory::randomCFG( const ext::deque<DefaultSymbolType>& nonterminals, const ext::deque<DefaultSymbolType> & terminals, double density ) { - if( terminals.size( ) <= 0 ) - throw exception::CommonException( "Terminals count must be greater than 0." ); - - if( nonterminals.size( ) <= 0 ) - throw exception::CommonException( "Nonterminals count must be greater than 0." ); - - grammar::CFG < > grammar(nonterminals.front()); - grammar.setTerminalAlphabet({terminals.begin(), terminals.end()}); - grammar.setNonterminalAlphabet({nonterminals.begin(), nonterminals.end()}); - - if(ext::random_devices::semirandom() % 2) - grammar.addRule(grammar.getInitialSymbol(), {}); - - int rules = 0; - while(rules < terminals.size() * nonterminals.size() * density / 100) { - const DefaultSymbolType& lhs = nonterminals[ext::random_devices::semirandom() % nonterminals.size()]; - - int rhsSize = ext::random_devices::semirandom() % 5; - ext::vector<ext::variant<DefaultSymbolType, DefaultSymbolType>> rhs; - int nonterminalsOnRHS = 0; - for(int i = 0; i < rhsSize; i++) { - if(ext::random_devices::semirandom() % (nonterminals.size() + terminals.size()) < nonterminals.size()) { - rhs.push_back(ext::variant < DefaultSymbolType, DefaultSymbolType > ( nonterminals[ext::random_devices::semirandom() % nonterminals.size()])); - nonterminalsOnRHS++; - } else { - rhs.push_back(ext::variant < DefaultSymbolType, DefaultSymbolType > ( terminals[ext::random_devices::semirandom() % terminals.size()])); - } - } - rules += nonterminalsOnRHS; - grammar.addRule(lhs, rhs); - } - - return grammar; -} +auto GenerateCFG2 = registration::AbstractRegister < RandomGrammarFactory, grammar::CFG < char, char >, size_t, size_t, bool, double> ( RandomGrammarFactory::generateCFG, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "nonterminalsCount", "terminalsCount", "randomizedAlphabet", "density" ); } /* namespace generate */ diff --git a/alib2algo/src/grammar/generate/RandomGrammarFactory.h b/alib2algo/src/grammar/generate/RandomGrammarFactory.h index 0c8644cfc8..bb04a85260 100644 --- a/alib2algo/src/grammar/generate/RandomGrammarFactory.h +++ b/alib2algo/src/grammar/generate/RandomGrammarFactory.h @@ -10,6 +10,10 @@ #include <alib/deque> #include <alib/set> +#include <alib/algorithm> +#include <alib/random> + +#include <exception/CommonException.h> #include <grammar/ContextFree/CFG.h> @@ -19,13 +23,59 @@ namespace generate { class RandomGrammarFactory { public: - static grammar::CFG < > generateCFG( ext::set<DefaultSymbolType> nonterminals, ext::set<DefaultSymbolType> terminals, double density ); - static grammar::CFG < > generateCFG( size_t nonterminalsCount, size_t terminalsSize, bool randomizedAlphabet, double density ); + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CFG < TerminalSymbolType, NonterminalSymbolType > generateCFG ( ext::set < NonterminalSymbolType > nonterminals, ext::set < TerminalSymbolType > terminals, double density ); + static grammar::CFG < char, char > generateCFG( size_t nonterminalsCount, size_t terminalsSize, bool randomizedAlphabet, double density ); private: - static grammar::CFG < > randomCFG( const ext::deque<DefaultSymbolType> & nonterminals, const ext::deque<DefaultSymbolType> & terminals, double density ); + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CFG < TerminalSymbolType, NonterminalSymbolType > randomCFG ( const ext::deque < NonterminalSymbolType > & nonterminals, const ext::deque < TerminalSymbolType > & terminals, double density ); }; +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CFG < TerminalSymbolType, NonterminalSymbolType > RandomGrammarFactory::generateCFG ( ext::set < NonterminalSymbolType > nonterminals, ext::set < TerminalSymbolType > terminals, double density ) { + ext::deque < TerminalSymbolType > terminals2 ( terminals.begin ( ), terminals.end ( ) ); + ext::deque < NonterminalSymbolType > nonterminals2 ( nonterminals.begin ( ), nonterminals.end ( ) ); + return RandomGrammarFactory::randomCFG ( nonterminals2, terminals2, density ); +} + +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CFG < TerminalSymbolType, NonterminalSymbolType > RandomGrammarFactory::randomCFG ( const ext::deque < NonterminalSymbolType > & nonterminals, const ext::deque < TerminalSymbolType > & terminals, double density ) { + if( terminals.size( ) <= 0 ) + throw exception::CommonException( "Terminals count must be greater than 0." ); + + if( nonterminals.size( ) <= 0 ) + throw exception::CommonException( "Nonterminals count must be greater than 0." ); + + grammar::CFG < TerminalSymbolType, NonterminalSymbolType > grammar(nonterminals.front()); + grammar.setTerminalAlphabet({terminals.begin(), terminals.end()}); + grammar.setNonterminalAlphabet({nonterminals.begin(), nonterminals.end()}); + + if(ext::random_devices::semirandom() % 2) + grammar.addRule(grammar.getInitialSymbol(), {}); + + int rules = 0; + while(rules < terminals.size() * nonterminals.size() * density / 100) { + const NonterminalSymbolType& lhs = nonterminals[ext::random_devices::semirandom() % nonterminals.size()]; + + int rhsSize = ext::random_devices::semirandom() % 5; + ext::vector<ext::variant<TerminalSymbolType, NonterminalSymbolType>> rhs; + int nonterminalsOnRHS = 0; + for(int i = 0; i < rhsSize; i++) { + if(ext::random_devices::semirandom() % (nonterminals.size() + terminals.size()) < nonterminals.size()) { + rhs.push_back(ext::variant < TerminalSymbolType, NonterminalSymbolType > ( nonterminals[ext::random_devices::semirandom() % nonterminals.size()])); + nonterminalsOnRHS++; + } else { + rhs.push_back(ext::variant < TerminalSymbolType, NonterminalSymbolType > ( terminals[ext::random_devices::semirandom() % terminals.size()])); + } + } + rules += nonterminalsOnRHS; + grammar.addRule(lhs, rhs); + } + + return grammar; +} + } /* namespace generate */ } /* namespace grammar */ diff --git a/alib2algo/test-src/playTest.cpp b/alib2algo/test-src/playTest.cpp index 01026b327f..edffe9234c 100644 --- a/alib2algo/test-src/playTest.cpp +++ b/alib2algo/test-src/playTest.cpp @@ -25,7 +25,7 @@ void playTest::setUp() void playTest::tearDown(){} -automaton::NFA < > playTest::randomNFA(void) const +automaton::NFA < char, unsigned > playTest::randomNFA(void) const { return automaton::generate::RandomAutomatonFactory::generateNFA( rand() % TEST_AUTOMATON_STATES_MAX + 1, diff --git a/alib2algo/test-src/playTest.h b/alib2algo/test-src/playTest.h index 635418fe82..77c48760c1 100644 --- a/alib2algo/test-src/playTest.h +++ b/alib2algo/test-src/playTest.h @@ -19,7 +19,7 @@ public: void testPlay1(); private: - automaton::NFA < > randomNFA(void) const; + automaton::NFA < char, unsigned > randomNFA(void) const; automaton::DFA < DefaultSymbolType, unsigned > mDFA(const automaton::NFA < > & automaton) const; void case1a(void) const; diff --git a/tests.anormalize.sh b/tests.anormalize.sh index c7e7e6ea6d..3025346028 100755 --- a/tests.anormalize.sh +++ b/tests.anormalize.sh @@ -64,7 +64,7 @@ function generateCFG { # $1 = command for conversion. Output of such command must be a grammar !! # $2 = original grammar function runTest2 { - GENERATED_STRINGS="./agenerate2 -t upTo --upto $STRING_LENGHTS" + GENERATED_STRINGS="./agenerate2 -t upTo --upto $STRING_LENGHTS | ./aecho2 -n" OUT=`timeout $TESTCASE_TIMEOUT bash -c "diff <(cat $2 | $1 | $GENERATED_STRINGS ) <(cat $2 | $GENERATED_STRINGS)"` RET=$? -- GitLab