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

add minimize generator

parent 185555a8
No related branches found
No related tags found
No related merge requests found
Pipeline #
/*
* RandomAutomatonFactory.cpp
*
* Created on: 6. 11. 2017
* Author: Jan Travnicek
*/
#include "MinimizeGenerator.h"
#include "RandomAutomatonFactory2.h"
#include <registration/AlgoRegistration.hpp>
#include <automaton/simplify/UnreachableStatesRemover.h>
#include <automaton/simplify/UselessStatesRemover.h>
#include <automaton/simplify/Minimize.h>
#include <exception/CommonException.h>
namespace automaton {
namespace generate {
automaton::DFA < char, unsigned > MinimizeGenerator::generateMinimizeDFA ( size_t statesMinimal, size_t statesDuplicates, size_t statesUnreachable, size_t statesUseless, size_t alphabetSize, bool randomizedAlphabet, double density, size_t expectedSteps ) {
size_t limit = 10000;
while ( limit -- ) {
automaton::DFA < char, unsigned > automaton = RandomAutomatonFactory2::generateDFA ( statesMinimal, statesDuplicates, statesUnreachable, statesUseless, alphabetSize, randomizedAlphabet, density );
size_t states = automaton.getStates ( ).size ( );
automaton::DFA < char, unsigned > unreachable = automaton::simplify::UnreachableStatesRemover::remove ( automaton );
if ( unreachable.getStates ( ).size ( ) + statesUnreachable != states )
continue;
states = unreachable.getStates ( ).size ( );
automaton::DFA < char, unsigned > useless = automaton::simplify::UselessStatesRemover::remove ( unreachable );
if ( useless.getStates ( ).size ( ) + statesUseless != states )
continue;
size_t steps;
states = useless.getStates ( ).size ( );
automaton::DFA < char, unsigned > minimal = automaton::simplify::Minimize::minimize ( useless, steps );
if ( ( expectedSteps != 0 && steps != expectedSteps ) || minimal.getStates ( ).size ( ) + statesDuplicates != states )
continue;
states = minimal.getStates ( ).size ( );
if ( statesMinimal != states )
continue;
return automaton;
}
throw exception::CommonException ( "Generating automaton for minimization failed." );
}
} /* namespace generate */
} /* namespace automaton */
namespace {
auto GenerateDFA = registration::AbstractRegister < automaton::generate::MinimizeGenerator, automaton::DFA < char, unsigned >, size_t, size_t, size_t, size_t, size_t, bool, double, size_t > ( automaton::generate::MinimizeGenerator::generateMinimizeDFA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesMinimal", "statesDuplicates", "statesUnreachable", "statesUseless", "alphabetSize", "randomizedAlphabet", "density", "steps" );
} /* namespace */
/*
* MinimizeGenerator.h
*
* Created on: 6. 11. 2017
* Author: Jan Travnicek
*/
#ifndef MINIMIZE_GENERATOR_H_
#define MINIMIZE_GENERATOR_H_
#include <automaton/FSM/DFA.h>
namespace automaton {
namespace generate {
class MinimizeGenerator {
public:
static automaton::DFA < char, unsigned > generateMinimizeDFA ( size_t statesMinimal, size_t statesDuplicates, size_t statesUnreachable, size_t statesUseless, size_t alphabetSize, bool randomizedAlphabet, double density, size_t expectedSteps );
};
} /* namespace generate */
} /* namespace automaton */
#endif /* MINIMIZE_GENERATOR_H_ */
/*
* RandomAutomatonFactory.cpp
*
* Created on: 5. 11. 2017
* Author: Jan Travnicek
*/
#include "RandomAutomatonFactory2.h"
#include <registration/AlgoRegistration.hpp>
namespace automaton {
namespace generate {
size_t RandomAutomatonFactory2::randomSourceState ( size_t statesMinimal, size_t visited, size_t depleted, const ext::deque < bool > & VStates, const ext::deque < bool > & DStates ) {
size_t y = ext::random_devices::semirandom() % ( visited - depleted ) + 1; // select y-th accessible state
for( size_t i = 0, cnt = 0; i < statesMinimal; i++ ) {
if( VStates [ i ] == true && DStates [ i ] == false )
cnt ++;
if( cnt == y )
return i;
}
return -1;
}
size_t RandomAutomatonFactory2::randomTargetState ( size_t statesMinimal, size_t visited, const ext::deque < bool > & VStates ) {
size_t z = ext::random_devices::semirandom() % ( statesMinimal - visited ) + 1; // select z-th inaccessible state
for( size_t i = 0, cnt = 0; i < statesMinimal; i++ ) {
if( VStates[ i ] == false )
cnt ++;
if( cnt == z )
return i;
}
return -1;
}
automaton::DFA < char, unsigned > RandomAutomatonFactory2::generateDFA( size_t statesMinimal, size_t statesDuplicates, size_t statesUnreachable, size_t statesUseless, size_t alphabetSize, bool randomizedAlphabet, double density ) {
if ( alphabetSize > 26 )
throw exception::CommonException("Too big alphabet.");
ext::vector < char > symbols;
for ( int i = 0; i < 26; i++ )
symbols.push_back ( i + 'a' );
if ( randomizedAlphabet )
shuffle ( symbols.begin ( ), symbols.end ( ), ext::random_devices::semirandom );
ext::deque < char > alphabet ( symbols.begin ( ), symbols.begin ( ) + alphabetSize );
return RandomAutomatonFactory2::NonminimalDFA ( statesMinimal, statesDuplicates, statesUnreachable, statesUseless, alphabet, density );
}
} /* namespace generate */
} /* namespace automaton */
namespace {
auto GenerateDFA = registration::AbstractRegister < automaton::generate::RandomAutomatonFactory2, automaton::DFA < char, unsigned >, size_t, size_t, size_t, size_t, size_t, bool, double > ( automaton::generate::RandomAutomatonFactory2::generateDFA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesMinimal", "statesDuplicates", "statesUnreachable", "statesUseless", "alphabetSize", "randomizedAlphabet", "density" );
} /* namespace */
/*
* RandomAutomatonFactory2.h
*
* Created on: 5. 11. 2017
* Author: Jan Travnicek
*/
#ifndef RANDOM_AUTOMATON_FACTORY_2_H_
#define RANDOM_AUTOMATON_FACTORY_2_H_
#include <deque>
#include <set>
#include <algorithm>
#include <random>
#include <exception/CommonException.h>
#include <automaton/FSM/DFA.h>
namespace automaton {
namespace generate {
class RandomAutomatonFactory2 {
public:
template < class SymbolType >
static automaton::DFA < SymbolType, unsigned > generateDFA ( size_t statesMinimal, size_t statesDuplicates, size_t statesUnreachable, size_t statesUseless, ext::set < SymbolType> alphabet, double density );
static automaton::DFA < char, unsigned > generateDFA ( size_t statesMinimal, size_t statesDuplicates, size_t statesUnreachable, size_t statesUseless, size_t alphabetSize, bool randomizedAlphabet, double density );
private:
static size_t randomSourceState ( size_t statesMinimal, size_t visited, size_t depleted, const ext::deque < bool > & Vstates, const ext::deque < bool > & DStates );
static size_t randomTargetState ( size_t statesMinimal, size_t visited, const ext::deque < bool > & VStates );
template < class SymbolType >
static size_t randomSymbol ( unsigned sourceState, const ext::deque < SymbolType > & alphabet, const automaton::DFA < SymbolType, unsigned > & automaton );
template < class SymbolType >
static void addTransition ( automaton::DFA < SymbolType, unsigned > & automaton, unsigned source, SymbolType symbol, unsigned target, const ext::deque < ext::vector < unsigned > > & duplicates );
template < class SymbolType >
static automaton::DFA < SymbolType, unsigned > NonminimalDFA( size_t statesMinimal, size_t statesDuplicates, size_t statesUnreachable, size_t statesUseless, const ext::deque < SymbolType > & alphabet, double density );
};
template < class SymbolType >
automaton::DFA < SymbolType, unsigned > RandomAutomatonFactory2::generateDFA( size_t statesMinimal, size_t statesDuplicates, size_t statesUnreachable, size_t statesUseless, ext::set < SymbolType > alphabet, double density ) {
ext::deque < SymbolType> alphabet2;
for( const auto & s : alphabet )
alphabet2.push_back ( s );
return RandomAutomatonFactory2::NonminimalDFA ( statesMinimal, statesDuplicates, statesUnreachable, statesUseless, alphabet, density );
}
template < class SymbolType >
size_t RandomAutomatonFactory2::randomSymbol ( unsigned sourceState, const ext::deque < SymbolType > & alphabet, const automaton::DFA < SymbolType, unsigned > & automaton ) {
size_t x = ext::random_devices::semirandom() % ( alphabet.size( ) - automaton.getTransitionsFromState ( sourceState ).size ( ) ) + 1;
for( size_t i = 0, cnt = 0; i < alphabet.size ( ); i++ ) {
if ( automaton.getTransitions ( ).find ( std::make_pair ( sourceState, alphabet [ i ] ) ) == automaton.getTransitions ( ).end ( ) )
cnt ++;
if( cnt == x )
return i;
}
return -1;
}
template < class SymbolType >
void RandomAutomatonFactory2::addTransition ( automaton::DFA < SymbolType, unsigned > & automaton, unsigned source, SymbolType symbol, unsigned target, const ext::deque < ext::vector < unsigned > > & duplicates ) {
for ( unsigned duplicateSource : duplicates [ source ] ) {
unsigned duplicateTarget = duplicates [ target ] [ ext::random_devices::semirandom() % ( duplicates [ target ].size ( ) ) ];
automaton.addTransition( duplicateSource, symbol, duplicateTarget );
}
}
template < class SymbolType >
automaton::DFA < SymbolType, unsigned > RandomAutomatonFactory2::NonminimalDFA( size_t statesMinimal, size_t statesDuplicates, size_t statesUnreachable, size_t statesUseless, const ext::deque < SymbolType > & alphabet, double density ) __attribute__ ((optnone)) {
if( alphabet.size( ) <= 0 )
throw exception::CommonException( "Alphabet size must be greater than 0." );
ext::deque < bool > VStates;
ext::deque < bool > FStates;
ext::deque < bool > DStates;
ext::deque < ext::vector < unsigned > > duplicates;
size_t visited;
size_t finals = 0;
size_t depleted = 0;
automaton::DFA < SymbolType, unsigned > automaton ( 0 );
for( const auto & s : alphabet )
automaton.addInputSymbol( s );
/* states partitioning -- | statesMinimal | statesUseless | statesUnreachable | statesDuplicates | */
for( unsigned i = 0; i < statesMinimal + statesUseless + statesUnreachable + statesDuplicates; i ++ ) {
VStates.push_back( false );
DStates.push_back( false );
FStates.push_back( false );
duplicates.push_back ( ext::vector < unsigned > { i } );
automaton.addState( i );
}
for ( unsigned i = 0; i < statesDuplicates; ++ i ) {
size_t a = ext::random_devices::semirandom() % ( statesMinimal );
duplicates [ a ].push_back ( i + statesMinimal + statesUseless + statesUnreachable );
}
// ---- base
if( statesMinimal == 0 ) {
return automaton;
} else if( statesMinimal == 1 ) {
addTransition( automaton, 0, alphabet[ ext::random_devices::semirandom() % alphabet.size( ) ], 0, duplicates );
visited = 1;
VStates[ 0 ] = true;
DStates[ 0 ] = automaton.getTransitionsFromState ( 0 ).size ( ) == alphabet.size ( );
if ( DStates[ 0 ] == true )
depleted ++;
} else {
size_t x = ( ext::random_devices::semirandom() % ( statesMinimal - 1 ) ) + 1;
addTransition( automaton, 0, alphabet[ ext::random_devices::semirandom() % alphabet.size( ) ], x, duplicates );
visited = 2;
VStates[ 0 ] = true;
VStates[ x ] = true;
DStates[ 0 ] = automaton.getTransitionsFromState ( 0 ).size ( ) == alphabet.size ( );
if ( DStates[ 0 ] == true )
depleted ++;
}
// ---- make statesMinimal reachable
while( visited != statesMinimal ) {
size_t a = randomSourceState ( statesMinimal, visited, depleted, VStates, DStates );
size_t b = randomTargetState ( statesMinimal, visited, VStates );
size_t c = randomSymbol ( a, alphabet, automaton );
addTransition( automaton, a, alphabet[ c ], b, duplicates );
visited ++;
VStates[ b ] = true;
DStates[ a ] = automaton.getTransitionsFromState ( a ).size ( ) == alphabet.size ( );
if ( DStates[ a ] == true )
depleted ++;
}
// ---- make statesUseless reachable
while( visited != statesMinimal + statesUseless ) {
size_t a = randomSourceState ( statesMinimal + statesUseless, visited, depleted, VStates, DStates );
size_t b = randomTargetState ( statesMinimal + statesUseless, visited, VStates );
size_t c = randomSymbol ( a, alphabet, automaton );
addTransition( automaton, a, alphabet[ c ], b, duplicates );
visited ++;
VStates[ b ] = true;
DStates[ a ] = automaton.getTransitionsFromState ( a ).size ( ) == alphabet.size ( );
if ( DStates[ a ] == true )
depleted ++;
}
unsigned last = 0;
for ( unsigned i = 0; i < statesMinimal; ++ i ) {
if ( automaton.getTransitionsFromState ( i ).size ( ) == 0 ) {
size_t c = randomSymbol ( i, alphabet, automaton );
addTransition ( automaton, i, alphabet [ c ], last, duplicates );
last = i;
}
}
for ( unsigned i = 0; i < statesMinimal / 2; ++ i ) {
size_t a = randomSourceState ( statesMinimal, visited - statesUseless, finals, VStates, FStates );
FStates [ a ] = true;
finals ++;
for ( unsigned s : duplicates [ a ] )
automaton.addFinalState ( s );
}
visited += statesUnreachable;
for ( unsigned i = 0; i < statesUnreachable; ++ i ) {
VStates [ statesMinimal + statesUseless + i ] = true;
}
double mnn100 = 100.0 / alphabet.size( ) / ( statesMinimal + statesUseless + statesUnreachable + statesDuplicates );
while( automaton.getTransitions ( ).size( ) * mnn100 < density ) {
size_t a = randomSourceState ( statesMinimal + statesUseless + statesUnreachable, visited, depleted, VStates, DStates );
size_t b;
if ( a < statesMinimal )
b = ext::random_devices::semirandom() % ( statesMinimal );
else if ( a < statesMinimal + statesUseless )
b = ext::random_devices::semirandom() % ( statesUseless ) + statesMinimal;
else
b = ext::random_devices::semirandom() % ( statesMinimal + statesUseless + statesUnreachable );
size_t c = randomSymbol ( a, alphabet, automaton );
addTransition( automaton, a, alphabet [ c ], b, duplicates );
DStates[ a ] = automaton.getTransitionsFromState ( a ).size ( ) == alphabet.size ( );
if ( DStates[ a ] == true )
depleted ++;
}
return automaton;
}
} /* namespace generate */
} /* namespace automaton */
#endif /* RANDOM_AUTOMATON_FACTORY_2_H_ */
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