Algorithms Library Toolkit
A toolkit for algorithms, especially for algorithms on formal languages
Normalize.h
Go to the documentation of this file.
1
6/*
7 * This file is part of Algorithms library toolkit.
8 * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)
9
10 * Algorithms library toolkit is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14
15 * Algorithms library toolkit is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19
20 * You should have received a copy of the GNU General Public License
21 * along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24#pragma once
25
26#include <automaton/FSM/DFA.h>
28#include <automaton/TA/DFTA.h>
29#include <automaton/PDA/DPDA.h>
31
32namespace automaton {
33
34namespace simplify {
35
44class Normalize {
45public:
57 template < class SymbolType, class StateType >
59
71 template < class SymbolType, class StateType >
73
87 template < class InputSymbolType, class PushdownStoreSymbolType, class StateType >
89
103 template < class InputSymbolType, class PushdownStoreSymbolType, class StateType >
105
118 template < class SymbolType, class StateType >
120};
121
122template < class SymbolType, class StateType >
124 unsigned counter = 0;
125 ext::map < StateType, unsigned > normalizationData;
126 ext::deque < StateType > processingData;
127
128 normalizationData.insert(std::make_pair(fsm.getInitialState(), counter++));
129 processingData.push_back(fsm.getInitialState());
130
131 while(!processingData.empty()) {
132 StateType current = std::move ( processingData.front() );
133 processingData.pop_front();
134
135 // Transitions are trivialy sorted by input symbol (from state is the same)
136 for(const std::pair < const ext::pair < StateType, SymbolType >, StateType > & transition : fsm.getTransitionsFromState(current) ) {
137 if(normalizationData.find(transition.second) == normalizationData.end()) {
138 normalizationData.insert ( std::make_pair ( transition.second, counter++ ) );
139 processingData.push_back ( transition.second );
140 }
141 }
142 }
143
144 if(normalizationData.size() != fsm.getStates().size()) {
145 throw exception::CommonException("Automaton normalize require minimal deterministic finite automaton");
146 }
147
148 automaton::DFA < SymbolType, unsigned > result( normalizationData.find ( fsm.getInitialState ( ) )->second );
149
150 result.setInputAlphabet(fsm.getInputAlphabet());
151
152 for(const StateType & state : fsm.getStates ( ) ) {
153 result.addState ( normalizationData.find ( state )->second );
154 }
155
156 for(const StateType & finalState : fsm.getFinalStates ( ) ) {
157 result.addFinalState( normalizationData.find ( finalState )->second );
158 }
159
160 for(const std::pair < const ext::pair < StateType, SymbolType >, StateType > & transition : fsm.getTransitions ( ) ) {
161 result.addTransition ( normalizationData.find ( transition.first.first )->second, transition.first.second, normalizationData.find ( transition.second )->second );
162 }
163
164 return result;
165}
166
167template < class SymbolType, class StateType >
169 unsigned counter = 0;
170 ext::map < StateType, unsigned > normalizationData;
171 ext::deque < StateType > processingData;
172
173 normalizationData.insert ( std::make_pair ( fsm.getInitialState ( ), counter ++ ) );
174 processingData.push_back ( fsm.getInitialState ( ) );
175
176 while ( ! processingData.empty ( ) ) {
177 StateType current = std::move ( processingData.front ( ) );
178 processingData.pop_front ( );
179
180 // Transitions are trivialy sorted by input sequence (from state is the same)
181 for ( const std::pair < const ext::pair < StateType, ext::vector < SymbolType > >, StateType > & transition : fsm.getTransitionsFromState ( current ) ) {
182 if ( normalizationData.find ( transition.second ) == normalizationData.end ( ) ) {
183 normalizationData.insert ( std::make_pair ( transition.second, counter ++ ) );
184 processingData.push_back ( transition.second );
185 }
186 }
187 }
188
189 if ( normalizationData.size ( ) != fsm.getStates ( ).size ( ) ) {
190 throw exception::CommonException ( "Automaton normalize require minimal deterministic finite automaton" );
191 }
192
193 automaton::CompactDFA < SymbolType, unsigned > result ( normalizationData.find ( fsm.getInitialState ( ) )->second );
194
195 result.setInputAlphabet ( fsm.getInputAlphabet ( ) );
196
197 for ( const StateType & state : fsm.getStates ( ) ) {
198 result.addState ( normalizationData.find ( state )->second );
199 }
200
201 for ( const StateType & finalState : fsm.getFinalStates ( ) ) {
202 result.addFinalState( normalizationData.find ( finalState )->second );
203 }
204
205 for ( const std::pair < const ext::pair < StateType, ext::vector < SymbolType > >, StateType > & transition : fsm.getTransitions ( ) ) {
206 result.addTransition ( normalizationData.find ( transition.first.first )->second, transition.first.second, normalizationData.find ( transition.second )->second );
207 }
208
209 return result;
210}
211
212template < class InputSymbolType, class PushdownStoreSymbolType, class StateType >
214 unsigned counterState = 0;
215 ext::map< StateType, unsigned > normalizationDataState;
216 unsigned counterSymbol = 0;
217 ext::map < InputSymbolType, unsigned > normalizationDataSymbol;
218 ext::deque < StateType > processingData;
219
220 normalizationDataState.insert(std::make_pair(pda.getInitialState(), counterState++));
221 normalizationDataSymbol.insert(std::make_pair(pda.getBottomOfTheStackSymbol(), counterSymbol++));
222 processingData.push_back(pda.getInitialState());
223
224 while(!processingData.empty()) {
225 StateType current = std::move ( processingData.front() );
226 processingData.pop_front();
227
228 for ( const std::pair < const ext::pair < StateType, common::symbol_or_epsilon < InputSymbolType > >, ext::pair < StateType, PushdownStoreSymbolType > > & transition : pda.getCallTransitions().equal_range ( ext::slice_comp ( current ) ) ) {
229 if ( ! normalizationDataState.contains ( transition.second.first ) ) {
230 normalizationDataState.insert ( std::make_pair ( transition.second.first, counterState ++ ) );
231 processingData.push_back ( transition.second.first );
232 }
233 if ( ! normalizationDataSymbol.contains ( transition.second.second ) ) {
234 normalizationDataSymbol.insert ( std::make_pair ( transition.second.second, counterSymbol ++ ) );
235 }
236 }
237 for ( const std::pair < const ext::pair < StateType, common::symbol_or_epsilon < InputSymbolType > >, StateType > & transition : pda.getLocalTransitions().equal_range ( ext::slice_comp ( current ) ) ) {
238 if ( ! normalizationDataState.contains ( transition.second ) ) {
239 normalizationDataState.insert ( std::make_pair ( transition.second, counterState ++ ) );
240 processingData.push_back ( transition.second );
241 }
242 }
243 bool allDone = true;
244 for ( const std::pair < const ext::tuple < StateType, common::symbol_or_epsilon < InputSymbolType >, PushdownStoreSymbolType >, StateType > & transition : pda.getReturnTransitions().equal_range ( ext::slice_comp ( current ) ) ) {
245 if ( normalizationDataSymbol.contains ( std::get < 2 > ( transition.first ) ) ) {
246 if ( ! normalizationDataState.contains ( transition.second ) ) {
247 normalizationDataState.insert ( std::make_pair ( transition.second, counterState ++ ) );
248 processingData.push_back ( transition.second );
249 }
250 } else {
251 allDone = false;
252 }
253 }
254 if ( ! allDone ) {
255 processingData.push_back ( std::move ( current ) );
256 }
257 }
258
259 if(normalizationDataState.size() != pda.getStates().size() || normalizationDataSymbol.size() != pda.getPushdownStoreAlphabet().size()) {
260 throw exception::CommonException("Automaton normalize require connected deterministic pushdown automaton");
261 }
262
263 automaton::RealTimeHeightDeterministicDPDA < InputSymbolType, unsigned, unsigned > result ( normalizationDataState.find ( pda.getInitialState ( ) )->second, normalizationDataSymbol.find ( pda.getBottomOfTheStackSymbol ( ) )->second );
264 result.setInputAlphabet(pda.getInputAlphabet());
265
266 for(const DefaultSymbolType & symbol : pda.getPushdownStoreAlphabet())
267 result.addPushdownStoreSymbol(normalizationDataSymbol.find(symbol)->second);
268
269 for(const DefaultStateType & state : pda.getStates())
270 result.addState ( normalizationDataState.find(state)->second);
271
272 for(const DefaultStateType & state : pda.getFinalStates())
273 result.addFinalState ( normalizationDataState.find(state)->second );
274
276 result.addCallTransition ( normalizationDataState.at ( transition.first.first ), transition.first.second, normalizationDataState.at ( transition.second.first ), normalizationDataSymbol.at ( transition.second.second ) );
277 }
278
279 for(const auto & transition : pda.getLocalTransitions()) {
280 result.addLocalTransition ( normalizationDataState.at ( transition.first.first ), transition.first.second, normalizationDataState.at ( transition.second ) );
281 }
282
283 for(const auto & transition : pda.getReturnTransitions()) {
284 result.addReturnTransition ( normalizationDataState.at ( std::get < 0 > ( transition.first ) ), std::get < 1 > ( transition.first ), normalizationDataSymbol.at ( std::get < 2 > ( transition.first ) ), normalizationDataState.at ( transition.second ) );
285 }
286
287 return result;
288}
289
290template < class InputSymbolType, class PushdownStoreSymbolType, class StateType >
292 unsigned counterState = 0;
293 ext::map< StateType, unsigned > normalizationDataState;
294 unsigned counterSymbol = 0;
295 ext::map < InputSymbolType, unsigned > normalizationDataSymbol;
296 ext::deque < StateType > processingData;
297
298 normalizationDataState.insert(std::make_pair(pda.getInitialState(), counterState++));
299 normalizationDataSymbol.insert(std::make_pair(pda.getInitialSymbol(), counterSymbol++));
300 processingData.push_back(pda.getInitialState());
301
302 while(!processingData.empty()) {
303 StateType current = std::move ( processingData.front() );
304 processingData.pop_front();
305
306 ext::map < std::pair < common::symbol_or_epsilon < InputSymbolType >, ext::vector < unsigned > >, std::pair < StateType, ext::vector < PushdownStoreSymbolType > > > transform;
307 bool stateFinished = true;
308 // For each transition from state current
310 // look whether all pop symbols are already transformed
311 if(std::all_of(std::get<2>(iter.first).begin(), std::get<2>(iter.first).end(), [&](const PushdownStoreSymbolType& symbol) { return normalizationDataSymbol.find(symbol) != normalizationDataSymbol.end(); })) {
312 ext::vector < unsigned > transformedSymbols;
313 // if so compute vector of transformed poped symbol -- this can be compared to other vectors of transformed symbols and the order can be trusted
314 for(const PushdownStoreSymbolType& symbol : std::get<2> ( iter.first ) ) {
315 transformedSymbols.push_back(normalizationDataSymbol.find(symbol)->second);
316 }
317
318 // then first order is by input symbol and the second is this vector transfomed symbols
319 transform.insert(std::make_pair(std::make_pair(std::get<1>(iter.first), transformedSymbols), iter.second));
320 } else {
321 stateFinished = false;
322 }
323 }
324 // if there was a single transition with undefined transformation for pop symbol process this state again later
325 if(!stateFinished) {
326 processingData.push_back(std::move ( current ) );
327 }
328 // now transitions are trivially sorted by input symbol and the already transformed symbols
329
330 // for each pair state, pushed symbols in order given by input symbol and transformed pop symbols
331 for(const auto& iter : transform) {
332 const auto& iters = iter.second;
333 // if the state is new assign a unique number to it and mark it for processing
334 if( normalizationDataState.find(iters.first) == normalizationDataState.end() ) {
335 normalizationDataState.insert(std::make_pair(iters.first, counterState++));
336 processingData.push_back(iters.first);
337 }
338 // if the symbols in order given by order of pushing are new assign a unique number to them
339 for(const PushdownStoreSymbolType & iter2 : iters.second) {
340 if( normalizationDataSymbol.find(iter2) == normalizationDataSymbol.end() ) {
341 normalizationDataSymbol.insert(std::make_pair(iter2, counterSymbol++));
342 }
343 }
344 }
345 }
346
347 if(normalizationDataState.size() != pda.getStates().size() || normalizationDataSymbol.size() != pda.getPushdownStoreAlphabet().size()) {
348 throw exception::CommonException("Automaton normalize require connected deterministic pushdown automaton");
349 }
350
351 automaton::DPDA < InputSymbolType, unsigned, unsigned > result ( normalizationDataState.find ( pda.getInitialState ( ) )->second, normalizationDataSymbol.find ( pda.getInitialSymbol ( ) )->second );
352 result.setInputAlphabet(pda.getInputAlphabet());
353
354 for(const DefaultSymbolType & symbol : pda.getPushdownStoreAlphabet())
355 result.addPushdownStoreSymbol(normalizationDataSymbol.find(symbol)->second);
356
357 for(const DefaultStateType & state : pda.getStates())
358 result.addState ( normalizationDataState.find(state)->second);
359
360 for(const DefaultStateType & state : pda.getFinalStates())
361 result.addFinalState ( normalizationDataState.find(state)->second );
362
363 for(const auto & transition : pda.getTransitions()) {
365 for(const auto& elem : std::get<2>(transition.first)) {
366 pop.push_back(normalizationDataSymbol.find(elem)->second);
367 }
369 for(const auto& elem : transition.second.second) {
370 push.push_back(normalizationDataSymbol.find(elem)->second);
371 }
372 result.addTransition ( normalizationDataState.find(std::get<0>(transition.first))->second, std::get<1>(transition.first), pop, normalizationDataState.find(transition.second.first)->second, push);
373 }
374
375 return result;
376}
377
378template < class SymbolType, class StateType >
380 unsigned counter = 0;
381 ext::map < StateType, unsigned > normalizationData;
382
383 auto isNormalized = [ & normalizationData ] ( const StateType & origName ) {
384 return normalizationData.count ( origName ) > 0;
385 };
386
388 do {
389 processing.clear ( );
390
391 // accumulate all transitions from normalized states to not yet normalized state
392 for ( const auto & transition : fta.getTransitions ( ) )
393 if ( std::all_of ( transition.first.second.begin ( ), transition.first.second.end ( ), isNormalized ) && ! isNormalized ( transition.second ) ) {
395 for ( const StateType & state : transition.first.second )
396 from.push_back ( normalizationData.at ( state ) );
397
398 processing.insert ( ext::make_pair ( transition.first.first, from ), transition.second );
399 }
400
401 for ( const std::pair < const ext::pair < common::ranked_symbol < SymbolType >, ext::vector < unsigned > >, StateType > & transition : processing )
402 // accumuated transition inducing normalization might have contained two or more transitions to the same state, but we want to normalize only once
403 if ( ! isNormalized ( transition.second ) )
404 normalizationData [ transition.second ] = counter ++;
405
406 } while ( !processing.empty ( ) );
407
408 if ( normalizationData.size ( ) != fta.getStates ( ).size ( ) ) {
409 throw exception::CommonException ( "Automaton normalize require minimal deterministic finite tree automaton" );
410 }
411
413 result.setInputAlphabet ( fta.getInputAlphabet ( ) );
414
415 for ( const StateType & state : fta.getStates ( ) ) {
416 result.addState ( normalizationData.at ( state ) );
417 }
418
419 for ( const StateType & finalState : fta.getFinalStates ( ) ) {
420 result.addFinalState ( normalizationData.at ( finalState ) );
421 }
422
423 for ( const auto & transition : fta.getTransitions ( ) ) {
424 ext::vector < unsigned > prevStates;
425 for ( const StateType & prev : transition.first.second )
426 prevStates.push_back ( normalizationData.at ( prev ) );
427
428 result.addTransition ( transition.first.first, prevStates, normalizationData.at ( transition.second ) );
429 }
430
431 return result;
432}
433
434} /* namespace simplify */
435
436} /* namespace automaton */
437
Compact deterministic finite automaton. Accepts regular languages. The automaton has a list of symbol...
Definition: CompactDFA.h:73
const ext::map< ext::pair< StateType, ext::vector< SymbolType > >, StateType > & getTransitions() const &
Definition: CompactDFA.h:483
const ext::set< StateType > & getFinalStates() const &
Definition: CompactDFA.h:192
const StateType & getInitialState() const &
Definition: CompactDFA.h:114
const ext::set< StateType > & getStates() const &
Definition: CompactDFA.h:143
ext::iterator_range< typename ext::map< ext::pair< StateType, ext::vector< SymbolType > >, StateType >::const_iterator > getTransitionsFromState(const StateType &from) const
Definition: CompactDFA.h:493
const ext::set< SymbolType > & getInputAlphabet() const &
Definition: CompactDFA.h:241
Deterministic finite automaton. Accepts regular languages.
Definition: DFA.h:71
const ext::set< StateType > & getFinalStates() const &
Definition: DFA.h:183
const ext::map< ext::pair< StateType, SymbolType >, StateType > & getTransitions() const &
Definition: DFA.h:473
const StateType & getInitialState() const &
Definition: DFA.h:105
const ext::set< SymbolType > & getInputAlphabet() const &
Definition: DFA.h:232
const ext::set< StateType > & getStates() const &
Definition: DFA.h:134
ext::iterator_range< typename ext::map< ext::pair< StateType, SymbolType >, StateType >::const_iterator > getTransitionsFromState(const StateType &from) const
Definition: DFA.h:483
Nondeterministic finite tree automaton without epsilon transitions. Accepts regular tree languages.
Definition: DFTA.h:74
const ext::map< ext::pair< common::ranked_symbol< SymbolType >, ext::vector< StateType > >, StateType > & getTransitions() const &
Definition: DFTA.h:289
const ext::set< common::ranked_symbol< SymbolType > > & getInputAlphabet() const &
Definition: DFTA.h:203
const ext::set< StateType > & getFinalStates() const &
Definition: DFTA.h:154
const ext::set< StateType > & getStates() const &
Definition: DFTA.h:105
Deterministic pushdown automaton. Accepts subset of context free languages.
Definition: DPDA.h:78
const PushdownStoreSymbolType & getInitialSymbol() const &
Definition: DPDA.h:301
const ext::set< PushdownStoreSymbolType > & getPushdownStoreAlphabet() const &
Definition: DPDA.h:243
const ext::set< InputSymbolType > & getInputAlphabet() const &
Definition: DPDA.h:330
ext::map< ext::tuple< StateType, common::symbol_or_epsilon< InputSymbolType >, ext::vector< PushdownStoreSymbolType > >, ext::pair< StateType, ext::vector< PushdownStoreSymbolType > > > getTransitionsFromState(const StateType &from) const
Definition: DPDA.h:692
const ext::set< StateType > & getStates() const &
Definition: DPDA.h:145
const ext::map< ext::tuple< StateType, common::symbol_or_epsilon< InputSymbolType >, ext::vector< PushdownStoreSymbolType > >, ext::pair< StateType, ext::vector< PushdownStoreSymbolType > > > & getTransitions() const &
Definition: DPDA.h:682
const ext::set< StateType > & getFinalStates() const &
Definition: DPDA.h:194
const StateType & getInitialState() const &
Definition: DPDA.h:116
Deterministic real time height deterministic pushdown automaton. Accepts subset of context free langu...
Definition: RealTimeHeightDeterministicDPDA.h:89
const ext::set< InputSymbolType > & getInputAlphabet() const &
Definition: RealTimeHeightDeterministicDPDA.h:363
const StateType & getInitialState() const &
Definition: RealTimeHeightDeterministicDPDA.h:149
const ext::map< ext::pair< StateType, common::symbol_or_epsilon< InputSymbolType > >, ext::pair< StateType, PushdownStoreSymbolType > > & getCallTransitions() const &
Definition: RealTimeHeightDeterministicDPDA.h:1062
const ext::set< PushdownStoreSymbolType > & getPushdownStoreAlphabet() const &
Definition: RealTimeHeightDeterministicDPDA.h:276
const ext::map< ext::pair< StateType, common::symbol_or_epsilon< InputSymbolType > >, StateType > & getLocalTransitions() const &
Definition: RealTimeHeightDeterministicDPDA.h:1082
const ext::map< ext::tuple< StateType, common::symbol_or_epsilon< InputSymbolType >, PushdownStoreSymbolType >, StateType > & getReturnTransitions() const &
Definition: RealTimeHeightDeterministicDPDA.h:1072
const ext::set< StateType > & getStates() const &
Definition: RealTimeHeightDeterministicDPDA.h:178
const ext::set< StateType > & getFinalStates() const &
Definition: RealTimeHeightDeterministicDPDA.h:227
const PushdownStoreSymbolType & getBottomOfTheStackSymbol() const &
Definition: RealTimeHeightDeterministicDPDA.h:334
Definition: Normalize.h:44
static automaton::DFA< SymbolType, unsigned > normalize(const automaton::DFA< SymbolType, StateType > &fsm)
Definition: Normalize.h:123
Definition: ranked_symbol.hpp:20
Definition: symbol_or_epsilon.hpp:24
Basic exception from which all other exceptions are derived.
Definition: CommonException.h:21
Class extending the deque class from the standard library. Original reason is to allow printing of th...
Definition: deque.hpp:44
Class extending the map class from the standard library. Original reason is to allow printing of the ...
Definition: map.hpp:48
R & at(const T &key, R &defaultValue)
Definition: map.hpp:163
std::pair< iterator, bool > insert(const T &key, const R &value)
Insert variant with explicit key and value parameters.
Definition: map.hpp:118
auto end() &
Inherited behavior of end for non-const instance.
Definition: map.hpp:215
Class extending the pair class from the standard library. Original reason is to allow printing of the...
Definition: pair.hpp:43
Class extending the tuple class from the standard library. Original reason is to allow printing of th...
Definition: tuple.hpp:42
Class extending the vector class from the standard library. Original reason is to allow printing of t...
Definition: vector.hpp:45
Definition: Object.h:16
typename T::StateType StateType
Definition: ToGrammarLeftRG.h:64
unsigned counter
Definition: Rename.h:247
for(const StateType &state :fsm.getStates()) renamingData.insert(std Rename::RenamedAutomaton< T > result(renamingData.at(fsm.getInitialState()))
Definition: Rename.h:253
Definition: ToGrammar.h:31
SliceComp< Ts ... > slice_comp(const Ts &... inst)
Definition: functional.hpp:95
ContainerType< ResType > transform(const ContainerType< InType, Ts ... > &in, Callback transform)
In container tranformation of all elements according to the tranform.
Definition: algorithm.hpp:150
all_of(T &&...) -> all_of< T... >
constexpr auto make_pair(T1 &&x, T2 &&y)
Definition: pair.hpp:79