Algorithms Library Toolkit
A toolkit for algorithms, especially for algorithms on formal languages
Minimize.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 <iomanip>
27
28#include <ext/sstream>
29
30#include <alib/map>
31#include <alib/set>
32
33#include <global/GlobalData.h>
34
35#include <automaton/FSM/DFA.h>
36#include <automaton/TA/DFTA.h>
37
38namespace automaton {
39
40namespace simplify {
41
51class Minimize {
52public:
61 template < class SymbolType, class StateType >
63 size_t steps;
64 return minimize ( dfa, steps );
65 }
66
76 template < class SymbolType, class StateType >
78
88 template < class SymbolType, class StateType >
90 size_t steps;
91 return minimize ( dfta, steps );
92 }
93
104 template < class SymbolType, class StateType >
106
107private:
108 template < class SymbolType, class StateType >
109 static void print_progress(const automaton::DFA < SymbolType, StateType >& dfa, const ext::map<std::pair<StateType, ext::set<std::pair<SymbolType, StateType> > >, ext::set<StateType> >& minimizedTransitionFunction, size_t iter);
110};
111
112template < class SymbolType, class StateType >
114 steps = 0;
115
116 if(dfa.getFinalStates().empty ( )) {
118 result.setInputAlphabet(dfa.getInputAlphabet());
119 return result;
120 }
121
123
124 for(const StateType& state : dfa.getStates())
126
127 for(const std::pair<const ext::pair<StateType, SymbolType>, StateType>& transition : dfa.getTransitions())
128 refactor[transition.first.first].insert(std::make_pair(transition.first.second, transition.second));
129
130 ext::map<StateType, StateType> toEquivalentStates; //original state to equivalent state
131 ext::map<std::pair<StateType, ext::set<std::pair<SymbolType, StateType> > >, ext::set<StateType> > minimizedTransitionFunction; //mapped to the original state
132
133 const StateType *firstFinal = nullptr;
134 const StateType *firstNonfinal = nullptr;
135 for(const StateType& state : dfa.getStates()) {
136 if(dfa.getFinalStates().count(state) == 0) { // not a final state
137 if(!firstNonfinal)
138 firstNonfinal = &state;
139 toEquivalentStates.insert(std::pair<StateType, StateType>(state, *firstNonfinal));
140 } else {
141 if(!firstFinal)
142 firstFinal = &state;
143 toEquivalentStates.insert(std::pair<StateType, StateType>(state, *firstFinal));
144 }
145 }
146
147 unsigned prevSize = 0;
148 while ( true ) {
149 for(const std::pair<const StateType, ext::map<SymbolType, StateType> >& transition : refactor) {
150 const StateType& from = toEquivalentStates.find(transition.first)->second;
152
153 for(const std::pair<const SymbolType, StateType> & transitionFromState : transition.second)
154 transitionFunction.insert(std::make_pair(transitionFromState.first, toEquivalentStates.find(transitionFromState.second)->second));
155
156 minimizedTransitionFunction[std::make_pair(from, transitionFunction)].insert(transition.first);
157 }
158
160 print_progress ( dfa, minimizedTransitionFunction, steps );
161
162 if (minimizedTransitionFunction.size() == prevSize)
163 break;
164
165 prevSize = minimizedTransitionFunction.size();
166 toEquivalentStates.clear();
167
168 for(const std::pair<const std::pair<StateType, ext::set<std::pair<SymbolType, StateType> > >, ext::set<StateType> >& transition : minimizedTransitionFunction)
169 for(const StateType& target : transition.second)
170 toEquivalentStates.insert(std::make_pair(target, *(transition.second.begin())));
171
172 minimizedTransitionFunction.clear();
173
174 ++ steps;
175 }
176
177 auto findInitialGroup = [ ] ( const ext::map < std::pair < StateType, ext::set < std::pair < SymbolType, StateType > > >, ext::set < StateType > > & transitions, const StateType & initialState ) {
178 for ( const std::pair < const std::pair < StateType, ext::set < std::pair < SymbolType, StateType > > >, ext::set < StateType > > & transition : transitions )
179 if ( transition.second.count ( initialState ) )
180 return transition.first.first;
181 throw std::logic_error ( "Initial group not identified." );
182 };
183
184 automaton::DFA < SymbolType, StateType > result( findInitialGroup ( minimizedTransitionFunction, dfa.getInitialState ( ) ) );
185
186 result.setInputAlphabet(dfa.getInputAlphabet());
187
188 for(const std::pair<const std::pair<StateType, ext::set<std::pair<SymbolType, StateType> > >, ext::set<StateType> >& transition : minimizedTransitionFunction) {
189 result.addState(transition.first.first);
190 if(dfa.getFinalStates().count(transition.first.first))
191 result.addFinalState(transition.first.first);
192 }
193
194 for(const std::pair<const std::pair<StateType, ext::set<std::pair<SymbolType, StateType> > >, ext::set<StateType> >& transition : minimizedTransitionFunction)
195 for(const std::pair<SymbolType, StateType>& transitionFromState : transition.first.second)
196 result.addTransition(transition.first.first, transitionFromState.first, transitionFromState.second);
197
198 return result;
199}
200
201#define RESETSS(x) {(x).clear(); (x).str("");}
202
203template < class SymbolType, class StateType >
204void Minimize::print_progress(const automaton::DFA < SymbolType, StateType >& dfa, const ext::map<std::pair<StateType, ext::set<std::pair<SymbolType, StateType> > >, ext::set<StateType> >& minimizedTransitionFunction, size_t iter) {
205 common::Streams::log << "delta " << iter << std::endl;
206
207 //ext::map<std::pair<StateType, ext::set<std::pair<SymbolType, StateType> > >, ext::set<StateType> > minimizedTransitionFunction; //mapped to the original state
208
209 /* need to restruct this first so we have table like: orig state | new state | trans_symb_1 | trans_symb_2 | ... | trans_symb_n */
210 // we surely have DFA here (transition map hence)
212 for(const auto& kv: minimizedTransitionFunction) {
213 for(const auto& state : kv.second) {
215 for(const auto& transition : kv.first.second) {
216 stateTransMap.insert(std::make_pair(transition.first, transition.second));
217 }
218 printMap.insert(std::make_pair(std::make_pair(state, kv.first.first), stateTransMap));
219 }
220 }
221
222 size_t stateWidth = 1;
223 size_t stateMapWidth = 1;
226
227 for(const SymbolType& symbol : dfa.getInputAlphabet()) {
228 ss << symbol;
229 colWidths[symbol] = ss.str().size();
230 RESETSS(ss);
231 }
232 for(const auto& kv : printMap) {
233 ss << kv.first.first;
234 stateWidth = std::max(stateWidth, ss.str().size());
235 RESETSS(ss);
236
237 ss << kv.first.second;
238 stateMapWidth = std::max(stateMapWidth, ss.str().size());
239 RESETSS(ss);
240
241 for(const SymbolType& symbol : dfa.getInputAlphabet()) {
242 auto it = kv.second.find(symbol);
243 if(it != kv.second.end()) {
244 ss << it -> second;
245 colWidths[symbol] = std::max(colWidths[symbol], ss.str().size());
246 RESETSS(ss);
247 }
248 }
249 }
250
251 common::Streams::log << std::setw(stateWidth) << "";
252 common::Streams::log << " | ";
253 common::Streams::log << std::setw(stateMapWidth) << "";
254 common::Streams::log << " | ";
255 for(const SymbolType& symbol : dfa.getInputAlphabet()) {
256 ss << symbol;
257 common::Streams::log << std::setw(colWidths[symbol]) << ss.str() << " | ";
258 RESETSS(ss);
259 }
260 common::Streams::log << std::endl;
261 for(const auto& kv : printMap) {
262 ss << kv.first.first;
263 common::Streams::log << std::setw(stateWidth) << ss.str() << " | ";
264 RESETSS(ss);
265
266 ss << kv.first.second;
267 common::Streams::log << std::setw(stateMapWidth) << ss.str() << " | ";
268 RESETSS(ss);
269
270 for(const auto& symbol : dfa.getInputAlphabet()) {
271 auto it = kv.second.find(symbol);
272 if(it != kv.second.end()) {
273 ss << it -> second;
274 common::Streams::log << std::setw(colWidths[symbol]) << ss.str();
275 RESETSS(ss);
276 }
277 else {
278 common::Streams::log << std::setw(colWidths[symbol]) << "";
279 }
280 common::Streams::log << " | ";
281 }
282 common::Streams::log << std::endl;
283 }
284 common::Streams::log << std::endl;
285}
286
287template < class SymbolType, class StateType >
290 result.setInputAlphabet(dfta.getInputAlphabet());
291
292 if (dfta.getFinalStates().empty ( ))
293 return result;
294
295 typedef std::pair < const ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > >, StateType > Transition;
296
298
299 for (const auto & state : dfta.getStates())
300 stateOccurences[state];
301
302 for(auto & transition : dfta.getTransitions()) {
303 const ext::vector<StateType> & from = transition.first.second;
304 for (size_t i = 0; i < from.size ( ); ++i)
305 stateOccurences[from[i]][transition].push_back(i);
306 }
307
308 ext::map <StateType, StateType> toEquivalentStates;
310 const StateType *firstFinal = nullptr;
311 const StateType *firstNonfinal = nullptr;
312 for (const StateType &state : dfta.getStates()) {
313 if (dfta.getFinalStates().count(state) == 0) { // not a final state
314 if (!firstNonfinal)
315 firstNonfinal = &state;
316
317 toEquivalentStates.insert(std::pair<StateType, StateType>(state, *firstNonfinal));
318 } else {
319 if (!firstFinal)
320 firstFinal = &state;
321
322 toEquivalentStates.insert(std::pair<StateType, StateType>(state, *firstFinal));
323 }
324 }
325
326 unsigned prevSize = 0;
327 steps = 0;
328 while(true) {
329 for(const auto & occurencesOfState : stateOccurences) {
330 const StateType & state = occurencesOfState.first;
331 const StateType & equivalentState = toEquivalentStates.find(state) -> second;
333
334 for(const auto & transitionOccurences : occurencesOfState.second) {
335 const auto & transition = transitionOccurences.first;
336 for ( size_t i : transitionOccurences.second) {
337 ext::vector<StateType> fromWithoutCurrent (transition.first.second);
338 fromWithoutCurrent.erase(fromWithoutCurrent.begin()+i);
339 keyTransitionsPart[ext::make_tuple(transition.first.first, fromWithoutCurrent, toEquivalentStates.find(transition.second)->second)].insert(i);
340 }
341 }
342
343 minimizedTransitionFunction [ std::make_pair ( equivalentState, keyTransitionsPart ) ].insert(state);
344 }
345
346 if (minimizedTransitionFunction.size() == prevSize)
347 break;
348
349 prevSize = minimizedTransitionFunction.size();
350 toEquivalentStates.clear();
351 for(const auto & transition : minimizedTransitionFunction)
352 for(const StateType & target : transition.second)
353 toEquivalentStates.insert(std::make_pair ( target, * transition.second.begin() ) );
354
355 minimizedTransitionFunction.clear();
356
357 ++ steps;
358 }
359
360 for (const auto & transition : minimizedTransitionFunction) {
361 const auto & state = *(transition.second.begin());
362 result.addState(state);
363 if(dfta.getFinalStates().count(state))
364 result.addFinalState(state);
365 }
366
367 for(const auto & transition : dfta.getTransitions()) {
369 from.reserve(transition.first.second.size());
370 for (const StateType & state : transition.first.second)
371 from.push_back(toEquivalentStates.find(state)->second);
372
373 result.addTransition(transition.first.first, from, toEquivalentStates.find(transition.second)->second);
374 }
375
376 return result;
377}
378
379} /* namespace simplify */
380
381} /* namespace automaton */
382
#define RESETSS(x)
Definition: Minimize.h:201
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
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
Definition: Minimize.h:51
static automaton::DFTA< SymbolType, StateType > minimize(const automaton::DFTA< SymbolType, StateType > &dfta)
Definition: Minimize.h:89
static automaton::DFA< SymbolType, StateType > minimize(const automaton::DFA< SymbolType, StateType > &dfa)
Definition: Minimize.h:62
static bool verbose
Verbose flag. Some algorithms print additional runtime information about internal datastructures or t...
Definition: GlobalData.h:24
static ext::reference_wrapper< ext::ostream > log
Standard loging stream. Mapped to descriptor 4.
Definition: GlobalData.h:78
Class extending the map class from the standard library. Original reason is to allow printing of the ...
Definition: map.hpp:48
std::pair< iterator, bool > insert(const T &key, const R &value)
Insert variant with explicit key and value parameters.
Definition: map.hpp:118
Definition: sstream.h:15
std::string str() const &
Definition: sstream.cpp:29
Class extending the pair class from the standard library. Original reason is to allow printing of the...
Definition: pair.hpp:43
Definition: set.hpp:44
Class extending the vector class from the standard library. Original reason is to allow printing of t...
Definition: vector.hpp:45
auto begin() &
Inherited behavior of begin for non-const instance.
Definition: vector.hpp:125
iterator erase(iterator pos)
Removes element from the container at position given by parameter pos.
Definition: vector.hpp:323
typename T::StateType StateType
Definition: ToGrammarLeftRG.h:64
int i
Definition: AllEpsilonClosure.h:118
typename T::SymbolType SymbolType
Definition: SingleInitialStateEpsilonTransition.h:72
transition first second
Definition: MinimizeByPartitioning.h:143
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
constexpr const T & max(const T &a)
Root case of maximum computation. The maximum from one value is the value itself.
Definition: algorithm.hpp:278
constexpr auto make_tuple(Elements &&... args)
Helper of extended tuple construction. The tuple is constructed from values pack, types are deduced.
Definition: tuple.hpp:203
constexpr auto make_pair(T1 &&x, T2 &&y)
Definition: pair.hpp:79