Skip to content
Snippets Groups Projects
RandomAutomatonFactory.cpp 4.31 KiB
Newer Older
/*
 * RandomAutomatonFactory.cpp
 *
 *  Created on: 27. 3. 2014
 *	  Author: Tomas Pecka
 */

#include "RandomAutomatonFactory.h"
Jan Trávníček's avatar
Jan Trávníček committed
#include <automaton/Automaton.h>
#include <exception/CommonException.h>
Jan Trávníček's avatar
Jan Trávníček committed
#include <algorithm>
#include <random>
namespace automaton {

namespace generate {
Jan Trávníček's avatar
Jan Trávníček committed
automaton::NFA < >  RandomAutomatonFactory::generateNFA( size_t statesCount, std::set<alphabet::Symbol> alphabet, double density ) {
	std::deque<alphabet::Symbol> alphabet2;
	for( const auto & s : alphabet )
		alphabet2.push_back( s );
	return RandomAutomatonFactory::LeslieConnectedNFA( statesCount, alphabet2, density );
}

Jan Trávníček's avatar
Jan Trávníček committed
automaton::NFA < >  RandomAutomatonFactory::generateNFA( size_t statesCount, size_t alphabetSize, bool randomizedAlphabet, double density ) {
	if(alphabetSize > 26)
		throw exception::CommonException("Too big alphabet.");
	std::vector<alphabet::Symbol> symbols;
	for(int i = 0; i < 26; i++) symbols.push_back(alphabet::symbolFrom(i + 'a'));
	if(randomizedAlphabet) shuffle(symbols.begin(), symbols.end(), std::random_devices::semirandom);
	std::deque<alphabet::Symbol> alphabet(symbols.begin(), symbols.begin() + alphabetSize);

	return RandomAutomatonFactory::LeslieConnectedNFA( statesCount, alphabet, density );
}

Jan Trávníček's avatar
Jan Trávníček committed
automaton::NFA < >  RandomAutomatonFactory::LeslieConnectedNFA( size_t n, const std::deque<alphabet::Symbol> & alphabet, double density ) {
	if( alphabet.size( ) <= 0 )
		throw exception::CommonException( "Alphabet size must be greater than 0." );

	std::deque<bool> VStates;
	std::deque<label::Label> Q;
	int unvisited;

Jan Trávníček's avatar
Jan Trávníček committed
	automaton::NFA < >  automaton( label::labelFrom( 0 ) );

	for( const auto & s : alphabet )
		automaton.addInputSymbol( s );

	for( size_t i = 0; i < n; i ++ ) {
		VStates.push_back( false );
		Q.push_back( label::labelFrom ( (int) i ) );
		automaton.addState( Q[ i ] );
	}

	if( n == 0 ) {
		return automaton;
	} else if( n == 1 ) {
		automaton.addTransition( Q[ 0 ], alphabet[ std::random_devices::semirandom() % alphabet.size( ) ], Q[ 0 ] );

		unvisited = 0;
		VStates[ 0 ] = true;
	} else {
		int x = ( std::random_devices::semirandom() % ( n - 1 ) ) + 1;
		automaton.addTransition( Q[ 0 ], alphabet[ std::random_devices::semirandom() % alphabet.size( ) ], Q[ x ] );
		unvisited = n - 2;

		VStates[ 0 ] = true;
		VStates[ x ] = true;
	}

	while( unvisited != 0 ) {
		size_t y = std::random_devices::semirandom() % ( n - unvisited ) + 1;	// select y-th   accessible state
		size_t z = std::random_devices::semirandom() % unvisited + 1;		// select z-th inaccessible state
		int a = -1, b = -1;

		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 = std::random_devices::semirandom() % alphabet.size( );
		automaton.addTransition( Q[ a ], alphabet[ c ], Q[ b ] );


		unvisited -= 1;
		VStates[ b ] = true;

		// ---------
	}

	for( const label::Label & q : Q ) {
		if( automaton.getTransitionsFromState( q ).size( ) == 0 && std::random_devices::semirandom() % 100 < 90 )
			automaton.addFinalState( q );
		else if( automaton.getTransitionsFromState( q ).size( ) > 0 && std::random_devices::semirandom() % 100 < 10 )
			automaton.addFinalState( q );
	}

	if( automaton.getFinalStates( ).size( ) == 0 ) {
		if( n == 1 ) {
			automaton.addFinalState( automaton.getInitialState( ) );
		} else {
			for( const label::Label & 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 = std::random_devices::semirandom() % n;
		int z = std::random_devices::semirandom() % n;
		int a = std::random_devices::semirandom() % alphabet.size();

		automaton.addTransition( Q[ y ], alphabet [ a ], Q[ z ] );
	}

	std::map<alphabet::Symbol, 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 */