From db165dc641cd157ded5d2c410c85888e42b13362 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: Wed, 29 Dec 2021 12:04:57 +0100
Subject: [PATCH] algo: make random automaton factory 3 more efficient

---
 .../src/automaton/RandomAutomatonFactory3.h   | 15 +++++++-------
 alib2std/src/extensions/algorithm.hpp         | 20 +++++++++++++++++++
 2 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/alib2algo_experimental/src/automaton/RandomAutomatonFactory3.h b/alib2algo_experimental/src/automaton/RandomAutomatonFactory3.h
index 6b883dcfcb..e41ec2032a 100644
--- a/alib2algo_experimental/src/automaton/RandomAutomatonFactory3.h
+++ b/alib2algo_experimental/src/automaton/RandomAutomatonFactory3.h
@@ -200,18 +200,17 @@ automaton::MultiInitialStateNFA < SymbolType, unsigned > RandomAutomatonFactory3
 	ext::vector < unsigned > unused = statesMinimal;
 	unused.erase ( std::find ( unused.begin ( ), unused.end ( ), initialState ) );
 
-	while ( visited.size ( ) != statesMinimal.size ( ) ) {
-		unsigned a = visited [ ext::random_devices::semirandom ( ) % visited.size ( ) ];
+	std::shuffle ( unused.begin ( ), unused.end ( ), ext::random_devices::semirandom );
 
-		if ( automaton.getTransitions ( ).count ( ext::slice_comp ( a ) ) == alphabet.size ( ) )
-			continue;
+	for ( unsigned b : unused ) {
+		unsigned a = * ext::randomValue ( visited.begin ( ), visited.end ( ), ext::random_devices::semirandom, [ & ] ( unsigned candidateState ) {
+			return automaton.getTransitions ( ).count ( ext::slice_comp ( candidateState ) ) != alphabet.size ( );
+		} );
 
 		size_t c = randomSymbol ( a, alphabet, automaton, deterministic );
-		size_t b = ext::random_devices::semirandom ( ) % unused.size ( );
 
-		addTransition( automaton, a, alphabet [ c ], unused [ b ], duplicates );
-		visited.push_back ( unused [ b ] );
-		unused.erase ( unused.begin ( ) + b );
+		addTransition( automaton, a, alphabet [ c ], b, duplicates );
+		visited.push_back ( b );
 	}
 
 	makeRelation ( automaton, alphabet, statesMinimal, statesMinimal, duplicates, density, deterministic );
diff --git a/alib2std/src/extensions/algorithm.hpp b/alib2std/src/extensions/algorithm.hpp
index b883e7e477..af56da78ec 100644
--- a/alib2std/src/extensions/algorithm.hpp
+++ b/alib2std/src/extensions/algorithm.hpp
@@ -416,5 +416,25 @@ inline bool range_contains_iterator ( ForwardIteratorBegin from, const ForwardIt
 	return false;
 }
 
+template < class Iterator, class RandomDevice >
+Iterator randomValue ( Iterator begin, Iterator end, RandomDevice && r ) {
+	if ( begin == end )
+		throw std::invalid_argument ( "Empty range to pick random value from." );
+	std::advance ( begin, r ( ) % std::distance ( begin, end ) );
+	return begin;
+}
+
+template < class Iterator, class RandomDevice, class Predicate >
+Iterator randomValue ( Iterator begin, Iterator end, RandomDevice r, Predicate p ) {
+	Iterator value = end;
+	size_t incidency = 0;
+
+	for ( ; begin != end; ++ begin )
+		if ( p ( * begin ) && ( r ( ) % ( ++ incidency ) ) < 1 )
+			value = begin;
+
+	return value;
+}
+
 } /* namespace ext */
 
-- 
GitLab