Vaucanson  1.4.1
minimization_hopcroft.hxx
1 // minimization_hopcroft.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, 2007, 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_HOPCROFT_HXX
18 # define VCSN_ALGORITHMS_MINIMIZATION_HOPCROFT_HXX
19 
20 # include <algorithm>
21 # include <list>
22 # include <queue>
23 # include <set>
24 # include <vector>
25 
26 # include <vaucanson/algebra/implementation/semiring/numerical_semiring.hh>
30 # include <vaucanson/automata/concept/automata_base.hh>
31 # include <vaucanson/misc/usual_macros.hh>
32 
33 # ifndef VCSN_NDEBUG
35 # endif // ! VCSN_NDEBUG
36 
37 namespace vcsn
38 {
39 
40  namespace internal
41  {
42  namespace hopcroft_minimization_det
43  {
44 
45 # define HOPCROFT_TYPES() \
46  typedef std::set<hstate_t> hstates_t; \
47  typedef std::vector<hstates_t> partition_t; \
48  typedef std::vector<unsigned> class_of_t; \
49  typedef std::queue<std::pair<hstates_t*, unsigned> > to_treat_t;
50 
54  template <typename input_t>
56  {
57  AUTOMATON_TYPES (input_t);
58  AUTOMATON_FREEMONOID_TYPES (input_t);
59  HOPCROFT_TYPES ();
60 
61  const input_t& input_;
62  hstates_t going_in_;
63  class_of_t& class_of_;
64  std::list<unsigned> maybe_splittable_;
65  std::vector<unsigned> count_for_;
66 
67  splitter_functor (const input_t& input, unsigned int max_state,
68  class_of_t& class_of)
69  : input_ (input), going_in_ (), class_of_(class_of),
70  count_for_ (max_state)
71  {}
72 
74  bool compute_states_going_in (const hstates_t& ss, letter_t l)
75  {
76  going_in_.clear ();
77  maybe_splittable_.clear ();
78  for_all_const_ (hstates_t, i, ss)
79  {
80  for (rdelta_iterator t(input_.value(), *i); ! t.done(); t.next())
81  {
82  monoid_elt_t w(input_.series_of(*t).structure().monoid(), l);
83  if (input_.series_of(*t).get(w) != input_.series().semiring().wzero_)
84  {
85  hstate_t s = input_.src_of(*t);
86  unsigned class_of_state = class_of_[s];
87 
88  if (count_for_[class_of_state] == 0)
89  maybe_splittable_.push_back (class_of_state);
90  count_for_[class_of_state]++;
91  going_in_.insert (s);
92  }
93  }
94  }
95  return not going_in_.empty ();
96  }
97 
99  void execute (partition_t& partition, to_treat_t& to_treat,
100  unsigned& n_partition)
101  {
102  for_all (std::list<unsigned>, inpartition, maybe_splittable_)
103  {
104  hstates_t& states = partition[*inpartition];
105  if (states.size () == count_for_[*inpartition])
106  { // All elements in states are predecessors, no split.
107  count_for_[*inpartition] = 0;
108  continue;
109  }
110  count_for_[*inpartition] = 0;
111  hstates_t states_inter_going_in;
112  hstates_t& states_minus_going_in = partition[n_partition];
113  // Compute @a states \ @a going_in_.
114  set_difference
115  (states.begin (), states.end (),
116  going_in_.begin (), going_in_.end (),
117  std::insert_iterator<hstates_t> (states_minus_going_in,
118  states_minus_going_in.begin ()));
119  // Compute @a states Inter @a going_in_.
120  set_intersection
121  (states.begin(), states.end (),
122  going_in_.begin (), going_in_.end (),
123  std::insert_iterator<hstates_t> (states_inter_going_in,
124  states_inter_going_in.begin ()));
125  // A split MUST occur.
126  assertion (not (states_inter_going_in.empty ()
127  or states_minus_going_in.empty ()));
128  // @a states must be the bigger one.
129  if (states_minus_going_in.size () > states_inter_going_in.size ())
130  {
131  states.swap (states_minus_going_in);
132  states_minus_going_in.swap (states_inter_going_in);
133  }
134  else
135  states.swap (states_inter_going_in);
136  for_all_const_ (hstates_t, istate, states_minus_going_in)
137  class_of_[*istate] = n_partition;
138  to_treat.push (std::make_pair (&states_minus_going_in,
139  n_partition++));
140  }
141  }
142  };
143 
145  template <typename input_t, typename output_t>
147  {
148  AUTOMATON_TYPES (input_t);
149  HOPCROFT_TYPES ();
150 
151  const input_t& input_;
152  output_t& output_;
153  const class_of_t& class_of_;
154 
155  unsigned src_;
156 
157  transition_adder_functor (const input_t& input, output_t& output,
158  const class_of_t& class_of)
159  : input_ (input), output_ (output), class_of_ (class_of)
160  {}
161 
163  void execute (hstate_t representative)
164  {
165  src_ = class_of_[representative];
166  for (delta_iterator t(input_.value(), representative); ! t.done(); t.next())
167  {
168  output_.add_series_transition (src_, class_of_[input_.dst_of (*t)],
169  input_.series_of (*t));
170  }
171  }
172  };
173  }
174  }
175 
176 
177  template <typename A, typename AI1, typename AI2>
178  void
179  do_hopcroft_minimization_det(const AutomataBase<A>&,
180  Element<A, AI2>& output,
181  const Element<A, AI1>& input)
182  {
183  typedef Element<A, AI1> input_t;
184  typedef Element<A, AI2> output_t;
185  AUTOMATON_TYPES (input_t);
186  AUTOMATON_FREEMONOID_TYPES (input_t);
187  HOPCROFT_TYPES ();
188 
189  using namespace internal::hopcroft_minimization_det;
190 
191  precondition(is_deterministic(input));
192 
193  unsigned max_state = input.states ().back () + 1;
194  partition_t partition (max_state);
195  class_of_t class_of (max_state);
196  to_treat_t to_treat;
197  unsigned n_partition = 0;
198  const alphabet_t& alphabet =
199  input.structure ().series ().monoid ().alphabet ();
200 
201  {
202  // Initialize Partition = {Q \ F , F }
203  hstates_t* finals = 0, * others = 0;
204  int n_finals = -1, n_others = -1,
205  count_finals = 0, count_others = 0;
206 
207 # define add_to_class(Name) \
208  do { \
209  if (not Name) \
210  { \
211  Name = &(partition[n_partition]); \
212  n_ ## Name = n_partition++; \
213  } \
214  count_ ## Name ++; \
215  (*Name).insert (*state); \
216  class_of[*state] = n_ ## Name; \
217  } while (0)
218 
219  for_all_const_states (state, input)
220  if (input.is_final (*state))
221  add_to_class (finals);
222  else
223  add_to_class (others);
224 # undef add_to_class
225 
226  if (n_partition == 0)
227  return;
228  if (n_partition == 1)
229  {
230  output = input;
231  return;
232  }
233  // Put F or Q \ F in the "To treat" list T.
234  if (count_finals > count_others)
235  to_treat.push (std::make_pair (others, n_others));
236  else
237  to_treat.push (std::make_pair (finals, n_finals));
238  }
239 
240  {
241  splitter_functor<input_t> splitter (input, max_state, class_of);
242 
243  // While T is not empty,
244  while (not to_treat.empty () && n_partition < max_state)
245  {
246  // Remove a set S of T ,
247  hstates_t& states = *(to_treat.front ().first);
248  to_treat.pop ();
249 
250  // For each letter l in Alphabet,
251  for_all_const_letters (letter, alphabet)
252  {
253  if (not splitter.compute_states_going_in (states, *letter))
254  continue;
255  splitter.execute (partition, to_treat, n_partition);
256  if (n_partition == max_state)
257  break;
258  }
259  }
260  }
261 
262  // Build the automaton.
263  // Assume that states are numbers starting from 0.
264  for (unsigned i = 0; i < n_partition; ++i)
265  output.add_state ();
266 
267  transition_adder_functor<input_t, output_t>
268  transition_adder (input, output, class_of);
269 
270  typename partition_t::iterator istates = partition.begin ();
271  for (unsigned i = 0; i < n_partition; ++i, ++istates)
272  {
273  hstate_t representative = *(*istates).begin();
274 
275  if (input.is_final (representative))
276  output.set_final (class_of[representative]);
277  transition_adder.execute (representative);
278  }
279 
280  for_all_const_initial_states (state, input)
281  output.set_initial (class_of[*state]);
282  }
283 
284 # undef HOPCROFT_TYPES
285 
295  template<typename A, typename AI>
296  Element<A, AI>
298  {
299  BENCH_TASK_SCOPED("minimization_hopcroft");
300  precondition(is_deterministic(a));
301  precondition(is_complete(a));
302  Element<A, AI> output(a.structure());
303  do_hopcroft_minimization_det(a.structure(), output, a);
304  return output;
305  }
306 
307 
308  /*-------------------------------------.
309  | Quotient with Boolean multiplicities |
310  `-------------------------------------*/
311  namespace internal
312  {
313  namespace hopcroft_minimization_undet
314  {
315 
316 # define QUOTIENT_TYPES() \
317  typedef std::list<hstate_t> partition_t; \
318  typedef std::vector<partition_t> partition_set_t; \
319  typedef typename partition_t::iterator partition_iterator; \
320  typedef std::vector<unsigned> class_of_t; \
321  typedef std::pair<unsigned, letter_t> pair_t; \
322  typedef std::list<pair_t> to_treat_t;
323 
324  template <typename input_t>
325  class quotient_splitter
326  {
327  public:
328  AUTOMATON_TYPES(input_t);
329  AUTOMATON_FREEMONOID_TYPES(input_t);
330  QUOTIENT_TYPES();
331 
332  typedef std::vector<bool> going_in_t;
333 
334  quotient_splitter (const automaton_t& input, class_of_t& class_of,
335  unsigned max_states)
336  : input_(input),
337  alphabet_(input.series().monoid().alphabet()),
338  class_(class_of),
339  count_for_(max_states, 0),
340  twin_(max_states, 0),
341  going_in_(max_states, false)
342  { }
343 
345  bool compute_going_in_states (partition_t& p, letter_t a)
346  {
347  for_all_(going_in_t, s, going_in_)
348  *s = false;
349 
350 
351  semiring_elt_t weight_zero = input_.series().semiring().wzero_;
352  monoid_elt_t w(input_.series().monoid(), a);
353 
354  for_all_(partition_t, s, p)
355  {
356  for (rdelta_iterator t(input_.value(), *s); ! t.done(); t.next())
357  {
358  series_set_elt_t st = input_.series_of(*t);
359  if (st.get(w) != weight_zero)
360  {
361  hstate_t s = input_.src_of(*t);
362  if (!going_in_[s])
363  {
365  going_in_[s] = true;
366  const unsigned i = class_[s];
367  if (count_for_[i] == 0)
368  met_class_.push_back(i);
369  count_for_[i]++;
370  }
371  }
372  }
373  }
374  return !met_class_.empty();
375  }
376 
378  void split (partition_set_t& parts, unsigned& max_partitions)
379  {
380  for_all_(std::list<unsigned>, klass, met_class_)
381  {
382  // if all states are predecessors there is no needed split
383  if (count_for_[*klass] == parts[*klass].size())
384  continue;
385 
386  if (twin_[*klass] == 0)
387  twin_[*klass] = max_partitions++;
388  unsigned new_klass = twin_[*klass];
389 
390  typename partition_t::iterator q;
391  for (typename partition_t::iterator next = parts[*klass].begin();
392  next != parts[*klass].end();)
393  {
394  q = next;
395  ++next;
396  if (going_in_[*q])
397  {
398  parts[new_klass].insert(parts[new_klass].end(), *q);
399  class_[*q] = new_klass;
400  parts[*klass].erase(q);
401  }
402  }
403  }
404  }
405 
406  void add_new_partitions(to_treat_t& to_treat,
407  const partition_set_t& part)
408  {
409  for_all_(std::list<unsigned>, klass, met_class_)
410  {
411  if (twin_[*klass] != 0)
412  {
413  for_all_const_letters(e, alphabet_)
414  {
415  if (find(to_treat.begin(), to_treat.end(), pair_t(*klass, *e)) !=
416  to_treat.end())
417  to_treat.push_back(pair_t(twin_[*klass], *e));
418  else
419  if (part[*klass].size() < part[twin_[*klass]].size())
420  to_treat.push_back(pair_t(*klass, *e));
421  else
422  to_treat.push_back(pair_t(twin_[*klass], *e));
423  }
424  }
425  }
426 
427  for_all_(std::list<unsigned>, klass, met_class_)
428  {
429  count_for_[*klass] = 0;
430  twin_[*klass] = 0;
431  }
432  met_class_.clear();
433  }
434 
435  private:
436  const automaton_t& input_;
437  const alphabet_t& alphabet_;
438  class_of_t& class_;
439  std::vector<unsigned> count_for_;
440  std::vector<unsigned> twin_;
441  going_in_t going_in_;
442  std::list<unsigned> met_class_;
443  };
444  }
445  }
446 
447  template <typename A, typename AI1, typename AI2>
448  void
449  do_quotient(const AutomataBase<A>&,
450  const algebra::NumericalSemiring&,
451  SELECTOR(bool),
452  Element<A, AI2>& output,
453  const Element<A, AI1>& input)
454  {
455  BENCH_TASK_SCOPED("do_quotient");
456 
457  typedef Element<A, AI1> input_t;
458  typedef Element<A, AI2> output_t;
459  AUTOMATON_TYPES(input_t);
460  AUTOMATON_FREEMONOID_TYPES(input_t);
461  QUOTIENT_TYPES();
462 
463  using namespace internal::hopcroft_minimization_undet;
464 
465  const alphabet_t& alphabet_(input.series().monoid().alphabet());
466  unsigned max_states = 0;
467 
468  for_all_const_states(i, input)
469  max_states = std::max(unsigned(*i), max_states);
470  ++max_states;
471 
472  /*--------------------------.
473  | To label the subsets of Q |
474  `--------------------------*/
475  unsigned max_partitions = 0;
476 
477  /*-----------------------------------------.
478  | To manage efficiently the partition of Q |
479  `-----------------------------------------*/
480  class_of_t class_(max_states);
481  partition_set_t part(max_states);
482 
483  /*-------------------------.
484  | To have a list of (P, a) |
485  `-------------------------*/
486  to_treat_t to_treat;
487 
488  /*-------------------------.
489  | Initialize the partition |
490  `-------------------------*/
491  BENCH_TASK_START("initialize partition");
492 
493  // In the general case, we have two sets, part[0] and part[1] One
494  // holds the final states, the other the non-final states. In
495  // some cases we may have only one set, for instance if we have no
496  // final states, or if we have only final states. Because we do
497  // not want to have an empty part[0], we will fill it with the
498  // first kind of state (final / non-final) we encounter.
499  unsigned final = 1;
500 
501  for_all_const_states (p, input)
502  {
503  unsigned c;
504  if (max_partitions == 0)
505  {
506  c = 0;
507  final = !input.is_final(*p);
508  }
509  else
510  {
511  c = input.is_final(*p) ? final : (1 - final);
512  }
513  class_[*p] = c;
514  part[c].insert(part[c].end(), *p);
515  max_partitions = std::max(max_partitions, c + 1);
516  }
517 
518  BENCH_TASK_STOP();
519 
520  /*------------------------------.
521  | Initialize the list of (P, a) |
522  `------------------------------*/
523  BENCH_TASK_START("initialize partition");
524 
525  if (max_partitions > 0)
526  for_all_const_letters (e, alphabet_)
527  to_treat.push_back(pair_t(0, *e));
528 
529  if (max_partitions > 1)
530  for_all_const_letters (e, alphabet_)
531  to_treat.push_back(pair_t(1, *e));
532 
533  BENCH_TASK_STOP();
534 
535  /*----------.
536  | Main loop |
537  `----------*/
538  BENCH_TASK_START("main loop");
539  {
540  quotient_splitter<input_t> splitter(input, class_, max_states);
541  while (!to_treat.empty())
542  {
543  BENCH_TASK_SCOPED("inner loop");
544  pair_t c = to_treat.front();
545  to_treat.pop_front();
546  unsigned p = c.first;
547  letter_t a = c.second;
548 
549  if (!splitter.compute_going_in_states(part[p], a))
550  continue;
551  {
552  BENCH_TASK_SCOPED("splitter.split");
553  splitter.split(part, max_partitions);
554  }
555  {
556  BENCH_TASK_SCOPED("splitter.add_new_partitions");
557  splitter.add_new_partitions(to_treat, part);
558  }
559  }
560  }
561 
562  BENCH_TASK_STOP();
563 
564  /*------------------------------------.
565  | Construction of the ouput automaton |
566  `------------------------------------*/
567  BENCH_TASK_START("construct output automaton");
568 
569  // Create the states
570  for (unsigned i = 0; i < max_partitions; ++i)
571  output.add_state();
572 
573  std::set<unsigned> already_linked;
574  for (unsigned i = 0; i < max_partitions; ++i)
575  {
576  // Get the first state of the partition => each state has the
577  // same behaviour
578  hstate_t s = part[i].front();
579 
580  if (input.is_final(s))
581  output.set_final(i);
582 
583  // Create the transitions
584  for_all_const_letters (e, alphabet_)
585  {
586  already_linked.clear();
587 
588  for (delta_iterator t(input.value(), s); ! t.done(); t.next())
589  {
590  monoid_elt_t w(input.series_of(*t).structure().monoid(), *e);
591  if (input.series_of(*t).get(w) != input.series().semiring().wzero_)
592  {
593  hstate_t out = input.dst_of(*t);
594  unsigned c = class_[out];
595  if (already_linked.find(c) == already_linked.end())
596  {
597  already_linked.insert(c);
598  output.add_letter_transition(i, c, *e);
599  }
600  }
601  }
602  }
603  }
604 
605  // Set initial states.
606  for_all_const_initial_states(i, input)
607  output.set_initial(class_[*i]);
608 
609  BENCH_TASK_STOP();
610  }
611 
612 # undef QUOTIENT_TYPES
613 
614 
615  /*----------------------------------------.
616  | Quotient with multiplicities (covering) |
617  `----------------------------------------*/
618 
619  template <class S, class T,
620  typename A, typename input_t, typename output_t>
621  void
622  do_quotient(const AutomataBase<A>& ,
623  const S& ,
624  const T& ,
625  output_t& output,
626  const input_t& input)
627  {
628  AUTOMATON_TYPES(input_t);
629  AUTOMATON_FREEMONOID_TYPES(input_t);
630  using namespace std;
631 
632  /*----------------------------------------.
633  | Declare data structures and variables. |
634  `----------------------------------------*/
635 
636  typedef set<htransition_t> set_transitions_t;
637  typedef set<hstate_t> set_states_t;
638  typedef set<semiring_elt_t> set_semiring_elt_t;
639  typedef vector<semiring_elt_t> vector_semiring_elt_t;
640  typedef pair<unsigned, letter_t> pair_class_letter_t;
641  typedef pair<hstate_t, semiring_elt_t> pair_state_semiring_elt_t;
642  typedef set<pair_state_semiring_elt_t> set_pair_state_semiring_elt_t;
643  typedef map<semiring_elt_t, unsigned> map_semiring_elt_t;
644 
645  series_set_elt_t null_series = input.series().zero_;
646  semiring_elt_t weight_zero = input.series().semiring().wzero_;
647  monoid_elt_t monoid_identity = input.series().monoid().VCSN_EMPTY_;
648  const alphabet_t& alphabet (input.series().monoid().alphabet());
649 
650  queue<pair_class_letter_t> the_queue;
651 
652  set<unsigned> met_classes;
653 
654  unsigned max_partition = 0;
655  unsigned max_states = 0;
656 
657  for_all_const_states(q, input)
658  max_states = std::max(unsigned (*q), max_states);
659  ++max_states;
660  // Avoid special case problem (one initial and final state...)
661  max_states = std::max(max_states, 2u);
662 
663  vector< vector<set_pair_state_semiring_elt_t> > inverse (max_states);
664 
665  map<letter_t, unsigned> pos_of_letter;
666 
667  unsigned max_pos = 0;
668 
669  for_all_const_letters(a, alphabet)
670  pos_of_letter[*a] = max_pos++;
671 
672  set_states_t states_visited;
673  set_semiring_elt_t semiring_had_class;
674  vector<set_states_t> classes (max_states);
675  vector<unsigned> class_of_state (max_states);
676  vector_semiring_elt_t old_weight (max_states);
677  map_semiring_elt_t class_of_weight;
678 
679  for (unsigned i = 0; i < max_states; ++i)
680  inverse[i].resize(max_pos);
681 
682  for_all_const_states(q, input)
683  for_all_const_letters(a, alphabet)
684  {
685 
686  for_all_const_(set_states_t, r, states_visited)
687  old_weight[*r] = weight_zero;
688  states_visited.clear();
689 
690  for (rdelta_iterator e(input.value(), *q); ! e.done(); e.next())
691  {
692  monoid_elt_t w(input.series_of(*e).structure().monoid(), *a);
693  if (input.series_of(*e).get(w) != input.series().semiring().wzero_)
694  {
695  hstate_t p = input.src_of(*e);
696  if (states_visited.find(p) != states_visited.end())
697  inverse[*q][pos_of_letter[*a]].
698  erase(pair_state_semiring_elt_t (p, old_weight[p]));
699  else
700  states_visited.insert(p);
701  series_set_elt_t sd = input.series_of(*e);
702  monoid_elt_t md (input.structure().series().monoid(), *a);
703  semiring_elt_t wsd = sd.get(md);
704  old_weight[p] += wsd;
705  inverse[*q][pos_of_letter[*a]].
706  insert(pair_state_semiring_elt_t (p, old_weight[p]));
707  }
708  }
709  }
710 
711  /*-----------------------------------------------------------.
712  | Initialize the partition with as many classes as there are |
713  | final values. |
714  `-----------------------------------------------------------*/
715 
716  bool empty = true;
717  unsigned class_non_final (0);
718 
719  for_all_const_states(q, input)
720  {
721  if (not input.is_final(*q))
722  {
723  if (empty == true)
724  {
725  empty = false;
726  class_non_final = max_partition;
727  max_partition++;
728  }
729  classes[class_non_final].insert(*q);
730  class_of_state[*q] = class_non_final;
731  }
732  else
733  {
734  semiring_elt_t w = input.get_final(*q).get(monoid_identity);
735  if (semiring_had_class.find(w) == semiring_had_class.end())
736  {
737  semiring_had_class.insert(w);
738  classes[max_partition].insert(*q);
739  class_of_weight[w] = max_partition;
740  class_of_state[*q] = max_partition;
741  max_partition++;
742  }
743  else
744  {
745  classes[class_of_weight[w]].insert(*q);
746  class_of_state[*q] = class_of_weight[w];
747  }
748  }
749  }
750 
751  /*-----------------------------------------------------.
752  | Initialize the queue with pairs <class_id, letter>. |
753  `-----------------------------------------------------*/
754 
755  for (unsigned i = 0; i < max_partition; i++)
756  for_all_const_letters(a, alphabet)
757  the_queue.push(pair_class_letter_t (i, *a));
758 
759  /*----------------.
760  | The main loop. |
761  `----------------*/
762 
763  unsigned old_max_partition = max_partition;
764 
765  while(not the_queue.empty())
766  {
767  pair_class_letter_t pair = the_queue.front();
768  the_queue.pop();
769  met_classes.clear();
770  vector_semiring_elt_t val (max_states);
771 
772  // FIXME: Isn't there an easier way to do this?
773  for_all_const_states(q, input)
774  val[*q] = 0;
775 
776  // First, calculate val[state] and not met_classes.
777  for_all_const_(set_states_t, q, classes[pair.first])
778  for_all_const_(set_pair_state_semiring_elt_t, pair_,
779  inverse[*q][pos_of_letter[pair.second]])
780  {
781  unsigned state = pair_->first;
782  if (met_classes.find(class_of_state[state]) ==
783  met_classes.end())
784  met_classes.insert(class_of_state[state]);
785  val[state] += pair_->second;
786  }
787 
788  // Next, for each met class, do the partition.
789  for_all_const_(set<unsigned>, class_id, met_classes)
790  {
791  if (classes[*class_id].size() == 1)
792  continue ;
793 
794  queue<hstate_t> to_erase;
795  semiring_elt_t next_val;
796  semiring_elt_t first_val = val[*(classes[*class_id].begin())];
797  class_of_weight.clear();
798  semiring_had_class.clear();
799 
800  for_all_const_(set_states_t, p, classes[*class_id])
801  {
802  next_val = val[*p];
803  // This state must be moved to another class!
804  if (next_val != first_val)
805  {
806  if (semiring_had_class.find(next_val) ==
807  semiring_had_class.end()) // Must create a new class
808  {
809  classes[max_partition].insert(*p);
810  class_of_state[*p] = max_partition;
811  semiring_had_class.insert(next_val);
812  class_of_weight[next_val] = max_partition;
813  max_partition++;
814  }
815  else
816  {
817  classes[class_of_weight[next_val]].insert(*p);
818  class_of_state[*p] = class_of_weight[next_val];
819  }
820  to_erase.push(*p);
821  }
822  }
823 
824  while(not to_erase.empty())
825  {
826  hstate_t s = to_erase.front();
827  to_erase.pop();
828  classes[*class_id].erase(s);
829  }
830 
831  // Push pairs <new_class_id, letter> into the queue.
832  for (unsigned i = old_max_partition; i < max_partition; i++)
833  for_all_const_letters(b, alphabet)
834  the_queue.push(pair_class_letter_t(i, *b));
835  old_max_partition = max_partition;
836  }
837  }
838 
839  /*------------------.
840  | Form the output. |
841  `------------------*/
842 
843  typedef vector<series_set_elt_t> vector_series_set_elt_t;
844 
845  std::vector<hstate_t> out_states (max_partition);
846 
847  // Add states.
848  for(unsigned i = 0; i < max_partition; i++)
849  {
850  out_states[i] = output.add_state();
851  hstate_t a_state = *classes[i].begin();
852  series_set_elt_t a_serie = null_series;
853 
854  for_all_const_(set_states_t, state, classes[i])
855  if(input.is_initial(*state))
856  a_serie += input.get_initial(*state);
857 
858  output.set_initial(out_states[i] , a_serie);
859 
860  if (input.is_final(a_state))
861  output.set_final(out_states[i] , input.get_final(a_state));
862  }
863 
864  // Add transitions.
865  vector_series_set_elt_t seriesof (max_partition, null_series);
866 
867  for(unsigned i = 0; i < max_partition; i++)
868  {
869  met_classes.clear();
870 
871  for (delta_iterator e(input.value(), *classes[i].begin()); ! e.done(); e.next())
872  {
873  series_set_elt_t se = input.series_of(*e);
874  unsigned cs = class_of_state[input.dst_of(*e)];
875 
876  if (met_classes.find(cs) == met_classes.end())
877  {
878  met_classes.insert(cs);
879  seriesof[cs] = se;
880  }
881  else
882  seriesof[cs] += se;
883  }
884 
885  for_all_const_(set<unsigned>, cs, met_classes)
886  if (seriesof[*cs] != null_series)
887  output.add_series_transition(out_states[i],
888  out_states[*cs],
889  seriesof[*cs]);
890  }
891  }
892 
893  template<typename A, typename AI>
894  Element<A, AI>
895  quotient(const Element<A, AI>& a)
896  {
897  BENCH_TASK_SCOPED("quotient");
898  precondition(is_realtime(a));
899  typedef Element<A, AI> automaton_t;
900  AUTOMATON_TYPES(automaton_t);
901  automaton_t output(a.structure());
902  do_quotient(a.structure(), a.structure().series().semiring(),
903  SELECT(semiring_elt_value_t), output, a);
904  return output;
905  }
906 
907 } // vcsn
908 
909 #endif // ! VCSN_ALGORITHMS_MINIMIZATION_HOPCROFT_HXX