Vaucanson  1.4.1
minimization_moore.hxx
1 // minimization_moore.hxx: this file is part of the Vaucanson project.
2 //
3 // Vaucanson, a generic library for finite state machines.
4 //
5 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 The Vaucanson Group.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // The complete GNU General Public Licence Notice can be found as the
13 // `COPYING' file in the root directory.
14 //
15 // The Vaucanson Group consists of people listed in the `AUTHORS' file.
16 //
17 #ifndef VCSN_ALGORITHMS_MINIMIZATION_MOORE_HXX
18 # define VCSN_ALGORITHMS_MINIMIZATION_MOORE_HXX
19 
23 
24 # ifndef VCSN_NDEBUG
26 # endif // ! VCSN_NDEBUG
27 
28 # include <vaucanson/automata/concept/handlers.hh>
29 # include <vaucanson/automata/concept/delta_kind.hh>
30 # include <vaucanson/misc/usual_macros.hh>
32 
33 # include <map>
34 # include <set>
35 # include <vector>
36 
37 // Useful macros for Moore's minimization.
38 
39 // Iterator on a list of groups.
40 # define for_all_groups(I, P) \
41  for (typename groupid_to_group_t::iterator I = ((P).begin()); I != (P).end(); ++I)
42 
43 // Iterator on state in a group. We don't iterate on the first not
44 // processed state.
45 # define for_all_state_in_groups(I, P) \
46  for (typename group_t::iterator I = ++((P).begin()); I != (P).end(); ++I)
47 
48 namespace vcsn {
49 
50  /*-------------------.
51  | minimization_moore |
52  `-------------------*/
53  // precondition : the input automaton is deterministic or
54  // co-deterministic according to Transposed
55  template<typename A, typename AI, bool Transposed>
56  void
57  do_minimization_moore(const Element<A, AI>& input, Element<A, AI>& output)
58  {
59  BENCH_TASK_SCOPED("minimization_moore");
60  typedef Element<A, AI> automaton_t;
61  AUTOMATON_TYPES(automaton_t);
62  AUTOMATON_FREEMONOID_TYPES(automaton_t);
63  using std::map;
64  using std::vector;
65  using std::set;
66 
67  // Consts.
68 
69  const hstate_t NullState;
70  const hstate_t NullGroup;
71  const alphabet_t& alphabet (input.series().monoid().alphabet());
72 
73  // Typedefs.
74 
75  typedef int letterid_t;
76  typedef int groupid_t;
77 
78  typedef set<hstate_t> group_t;
79  typedef vector<group_t> groupid_to_group_t;
80 
81  typedef vector<hstate_t> letterid_to_state_t;
82 
83  typedef map<hstate_t, letterid_to_state_t> state_to_letterid_to_state_t;
84 
85  typedef map<hstate_t, groupid_t> state_to_groupid_t;
86  typedef map<letter_t, letterid_t> letter_to_letterid_t;
87 
88  /*---------------.
89  | Initialization |
90  `---------------*/
91 
92  precondition(input.exists());
93 
94  groupid_to_group_t groupid_to_group(input.states().size());
95 
96  state_to_groupid_t state_to_groupid;
97  state_to_groupid[NullState] = NullGroup;
98 
99  letter_to_letterid_t letter_to_letterid;
100  int letter_count = 0;
101  for_all_const_letters(iletter, alphabet)
102  letter_to_letterid[*iletter] = letter_count++;
103 
104  state_to_letterid_to_state_t aut_view;
105  for_all_const_states(istate, input)
106  {
107  aut_view[*istate] = letterid_to_state_t(letter_count, NullState);
108  if ((not Transposed and input.is_final(*istate)) or
109  (Transposed and input.is_initial(*istate)))
110  {
111  groupid_to_group[0].insert(*istate);
112  state_to_groupid[*istate] = 0;
113  }
114  else
115  {
116  groupid_to_group[1].insert(*istate);
117  state_to_groupid[*istate] = 1;
118  }
119  }
120 
121  for_all_const_states(istate, input)
122  {
123  for_all_const_(letter_to_letterid_t, iletter, letter_to_letterid)
124  {
125  bool empty = true;
126  hstate_t first;
127  if (not Transposed)
128  {
129  for (delta_iterator t(input.value(), *istate);
130  ! t.done() && empty;
131  t.next())
132  {
133  monoid_elt_t w(input.series_of(*t).structure().monoid(), iletter->first);
134  if (input.series_of(*t).get(w) != input.series().semiring().wzero_)
135  {
136  empty = false;
137  first = input.dst_of(*t);
138  break;
139  }
140  }
141  }
142  else
143  {
144  for (rdelta_iterator t(input.value(), *istate);
145  ! t.done() && empty;
146  t.next())
147  {
148  monoid_elt_t w(input.series_of(*t).structure().monoid(), iletter->first);
149  if (input.series_of(*t).get(w) != input.series().semiring().wzero_)
150  {
151  empty = false;
152  first = input.src_of(*t);
153  break;
154  }
155  }
156  }
157  if (not empty)
158  aut_view[*istate][iletter->second] = first;
159  }
160  }
161 
162 
163  /*-----.
164  | Loop |
165  `-----*/
166 
167  int last_group = 1;
168  for (bool group_modified = true; group_modified;)
169  {
170  group_modified = false;
171  for_all_groups(igroup, groupid_to_group)
172  {
173  if (igroup->empty())
174  break;
175 
176  hstate_t first_state = *(igroup->begin());
177  bool group_created = false;
178 
179  for_all_state_in_groups(istate, *igroup)
180  {
181  int i;
182  for (i = 0; i < letter_count; ++i)
183  if (state_to_groupid[aut_view[first_state][i]] !=
184  state_to_groupid[aut_view[*istate][i]])
185  break;
186  if (i != letter_count)
187  {
188  typename group_t::iterator istate_save = istate;
189 
190  istate_save--;
191  if (group_created == false)
192  {
193  last_group++;
194  group_created = true;
195  group_modified = true;
196  }
197  groupid_to_group[last_group].insert(*istate);
198  state_to_groupid[*istate] = last_group;
199  igroup->erase(*istate);
200  istate = istate_save;
201  }
202  }
203  }
204  }
205 
206 
207  /*-----------------------.
208  | Automaton construction |
209  `-----------------------*/
210 
211  std::vector<hstate_t> new_states(last_group + 1);
212 
213  // Create all states.
214  for (int i = 0; i <= last_group; ++i)
215  new_states[i] = output.add_state();
216 
217  // Create all transitions.
218  for (int i = 0; i <= last_group; ++i)
219  {
220  hstate_t repres = *(groupid_to_group[i].begin());
221 
222  for_all_const_(letter_to_letterid_t, iletter, letter_to_letterid)
223  if (aut_view[repres][iletter->second] != NullState)
224  {
225  if (not Transposed)
226  output.add_letter_transition(new_states[i],
227  new_states[state_to_groupid
228  [aut_view[repres]
229  [iletter->second]]],
230  iletter->first);
231  else
232  output.add_letter_transition(new_states[state_to_groupid
233  [aut_view[repres]
234  [iletter->second]]],
235  new_states[i],
236  iletter->first);
237  }
238  }
239 
240  // Setting initial and final states.
241  if (not Transposed)
242  {
243  output.set_final(new_states[0]);
244  output.set_initial(new_states[state_to_groupid[*input.initial().begin()]]);
245  }
246  else
247  {
248  output.set_initial(new_states[0]);
249  output.set_final(new_states[state_to_groupid[*input.final().begin()]]);
250  }
251 
252  }
253 
254 
255  template<typename A, typename AI>
256  void
258  {
259  precondition(is_deterministic(a));
260  precondition(is_complete(a));
261  Element<A, AI> output(a.structure());
262  do_minimization_moore<A, AI, false>(a, output);
263  a = output;
264  }
265 
266 
267  template<typename A, typename AI>
268  Element<A, AI>
270  {
271  precondition(is_deterministic(a));
272  precondition(is_complete(a));
273  Element<A, AI> output(a.structure());
274  do_minimization_moore<A, AI, false>(a, output);
275  return output;
276  }
277 
278  template<typename A, typename AI>
279  void
281  {
282  precondition(is_deterministic(transpose(a)));
283  precondition(is_complete(transpose(a)));
284  Element<A, AI> output(a.structure());
285  do_minimization_moore<A, AI, true>(a, output);
286  a = output;
287  }
288 
289 
290  template<typename A, typename AI>
291  Element<A, AI>
293  {
294  precondition(is_deterministic(transpose(a)));
295  precondition(is_complete(transpose(a)));
296  Element<A, AI> output(a.structure());
297  do_minimization_moore<A, AI, true>(a, output);
298  return output;
299  }
300 
301 } // vcsn
302 
303 // Prevent potential conflicts.
304 # undef for_all_groups
305 # undef for_all_state_in_groups
306 
307 
308 #endif // ! VCSN_ALGORITHMS_MINIMIZATION_MOORE_HXX