Skip to content
Snippets Groups Projects
Commit de75b2c0 authored by Jan Trávníček's avatar Jan Trávníček
Browse files

template random automaton and grammar factory

parent d9d6aca3
No related branches found
No related tags found
No related merge requests found
Pipeline #
......@@ -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 */
 
......
......@@ -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 */
......
......@@ -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 */
 
......
......@@ -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 */
......
......@@ -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,
......
......@@ -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;
......
......@@ -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=$?
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment