00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef VCSN_ALGORITHMS_MINIMIZATION_HOPCROFT_HXX
00018 # define VCSN_ALGORITHMS_MINIMIZATION_HOPCROFT_HXX
00019
00020 # include <algorithm>
00021 # include <list>
00022 # include <queue>
00023 # include <set>
00024 # include <vector>
00025
00026 # include <vaucanson/algebra/implementation/semiring/numerical_semiring.hh>
00027 # include <vaucanson/algorithms/minimization_hopcroft.hh>
00028 # include <vaucanson/automata/concept/automata_base.hh>
00029 # include <vaucanson/misc/usual_macros.hh>
00030 # include <vaucanson/misc/bitset.hh>
00031
00032 namespace vcsn
00033 {
00034
00035 namespace internal
00036 {
00037 namespace hopcroft_minimization_det
00038 {
00039
00040 # define HOPCROFT_TYPES() \
00041 typedef std::set<hstate_t> hstates_t; \
00042 typedef std::vector<hstates_t> partition_t; \
00043 typedef std::vector<unsigned> class_of_t; \
00044 typedef std::queue<std::pair<hstates_t*, unsigned> > to_treat_t;
00045
00050 template <typename input_t>
00051 struct splitter_functor
00052 {
00053 AUTOMATON_TYPES (input_t);
00054 AUTOMATON_FREEMONOID_TYPES (input_t);
00055 HOPCROFT_TYPES ();
00056
00057 const input_t& input_;
00058 hstates_t going_in_;
00059 class_of_t& class_of_;
00060 std::list<unsigned> maybe_splittable_;
00061 std::vector<unsigned> count_for_;
00062
00063 splitter_functor (const input_t& input, unsigned int max_state,
00064 class_of_t& class_of)
00065 : input_ (input), going_in_ (), class_of_(class_of),
00066 count_for_ (max_state)
00067 {}
00068
00070 bool compute_states_going_in (const hstates_t& ss, letter_t l)
00071 {
00072 going_in_.clear ();
00073 maybe_splittable_.clear ();
00074 for_all_const_ (hstates_t, i, ss)
00075 input_.letter_rdeltaf (*this, *i, l, delta_kind::states ());
00076 return not going_in_.empty ();
00077 }
00078
00080 void operator () (hstate_t state)
00081 {
00082 unsigned class_of_state = class_of_[state];
00083
00084 if (count_for_[class_of_state] == 0)
00085 maybe_splittable_.push_back (class_of_state);
00086 count_for_[class_of_state]++;
00087 going_in_.insert (state);
00088 }
00089
00091 void execute (partition_t& partition, to_treat_t& to_treat,
00092 unsigned& n_partition)
00093 {
00094 for_all (std::list<unsigned>, inpartition, maybe_splittable_)
00095 {
00096 hstates_t& states = partition[*inpartition];
00097 if (states.size () == count_for_[*inpartition])
00098 {
00099 count_for_[*inpartition] = 0;
00100 continue;
00101 }
00102 count_for_[*inpartition] = 0;
00103 hstates_t states_inter_going_in;
00104 hstates_t& states_minus_going_in = partition[n_partition];
00105
00106 set_difference
00107 (states.begin (), states.end (),
00108 going_in_.begin (), going_in_.end (),
00109 std::insert_iterator<hstates_t> (states_minus_going_in,
00110 states_minus_going_in.begin ()));
00111
00112 set_intersection
00113 (states.begin(), states.end (),
00114 going_in_.begin (), going_in_.end (),
00115 std::insert_iterator<hstates_t> (states_inter_going_in,
00116 states_inter_going_in.begin ()));
00117
00118 assertion (not (states_inter_going_in.empty ()
00119 or states_minus_going_in.empty ()));
00120
00121 if (states_minus_going_in.size () > states_inter_going_in.size ())
00122 {
00123 states.swap (states_minus_going_in);
00124 states_minus_going_in.swap (states_inter_going_in);
00125 }
00126 else
00127 states.swap (states_inter_going_in);
00128 for_all_const_ (hstates_t, istate, states_minus_going_in)
00129 class_of_[*istate] = n_partition;
00130 to_treat.push (std::make_pair (&states_minus_going_in,
00131 n_partition++));
00132 }
00133 }
00134 };
00135
00137 template <typename input_t, typename output_t>
00138 struct transition_adder_functor
00139 {
00140 AUTOMATON_TYPES (input_t);
00141 HOPCROFT_TYPES ();
00142
00143 const input_t& input_;
00144 output_t& output_;
00145 const class_of_t& class_of_;
00146
00147 unsigned src_;
00148
00149 transition_adder_functor (const input_t& input, output_t& output,
00150 const class_of_t& class_of)
00151 : input_ (input), output_ (output), class_of_ (class_of)
00152 {}
00153
00155 void execute (hstate_t representative)
00156 {
00157 src_ = class_of_[representative];
00158 input_.deltaf (*this, representative, delta_kind::transitions ());
00159 }
00160
00161 void operator () (htransition_t t)
00162 {
00163 output_.add_series_transition (src_, class_of_[input_.dst_of (t)],
00164 input_.series_of (t));
00165 }
00166 };
00167 }
00168 }
00169
00170
00171 template <typename A, typename input_t, typename output_t>
00172 void
00173 do_hopcroft_minimization_det(const AutomataBase<A>& ,
00174 output_t& output,
00175 const input_t& input)
00176 {
00177 AUTOMATON_TYPES (input_t);
00178 AUTOMATON_FREEMONOID_TYPES (input_t);
00179 HOPCROFT_TYPES ();
00180
00181 using namespace internal::hopcroft_minimization_det;
00182
00183 unsigned max_state = input.states ().back () + 1;
00184 partition_t partition (max_state);
00185 class_of_t class_of (max_state);
00186 to_treat_t to_treat;
00187 unsigned n_partition = 0;
00188 const alphabet_t& alphabet =
00189 input.structure ().series ().monoid ().alphabet ();
00190
00191 {
00192
00193 hstates_t* finals = 0, * others = 0;
00194 int n_finals = -1, n_others = -1,
00195 count_finals = 0, count_others = 0;
00196
00197 # define add_to_class(Name) \
00198 do { \
00199 if (not Name) \
00200 { \
00201 Name = &(partition[n_partition]); \
00202 n_ ## Name = n_partition++; \
00203 } \
00204 count_ ## Name ++; \
00205 (*Name).insert (*state); \
00206 class_of[*state] = n_ ## Name; \
00207 } while (0)
00208
00209 for_all_const_states (state, input)
00210 if (input.is_final (*state))
00211 add_to_class (finals);
00212 else
00213 add_to_class (others);
00214 # undef add_to_class
00215
00216 if (n_partition == 0)
00217 return;
00218 if (n_partition == 1)
00219 {
00220 output = input;
00221 return;
00222 }
00223
00224 if (count_finals > count_others)
00225 to_treat.push (std::make_pair (others, n_others));
00226 else
00227 to_treat.push (std::make_pair (finals, n_finals));
00228 }
00229
00230 {
00231 splitter_functor<input_t> splitter (input, max_state, class_of);
00232
00233
00234 while (not to_treat.empty () && n_partition < max_state)
00235 {
00236
00237 hstates_t& states = *(to_treat.front ().first);
00238 to_treat.pop ();
00239
00240
00241 for_all_const_letters (letter, alphabet)
00242 {
00243 if (not splitter.compute_states_going_in (states, *letter))
00244 continue;
00245 splitter.execute (partition, to_treat, n_partition);
00246 if (n_partition == max_state)
00247 break;
00248 }
00249 }
00250 }
00251
00252
00253
00254 for (unsigned i = 0; i < n_partition; ++i)
00255 output.add_state ();
00256
00257 transition_adder_functor<input_t, output_t>
00258 transition_adder (input, output, class_of);
00259
00260 typename partition_t::iterator istates = partition.begin ();
00261 for (unsigned i = 0; i < n_partition; ++i, ++istates)
00262 {
00263 hstate_t representative = *(*istates).begin();
00264
00265 if (input.is_final (representative))
00266 output.set_final (class_of[representative]);
00267 transition_adder.execute (representative);
00268 }
00269
00270 for_all_const_initial_states (state, input)
00271 output.set_initial (class_of[*state]);
00272 }
00273
00274 # undef HOPCROFT_TYPES
00275
00284 template<typename A, typename T>
00285 Element<A, T>
00286 minimization_hopcroft(const Element<A, T>& a)
00287 {
00288 TIMER_SCOPED ("minimization_hopcroft");
00289 Element<A, T> output(a.structure());
00290 do_hopcroft_minimization_det(a.structure(), output, a);
00291 return output;
00292 }
00293
00294
00295
00296
00297
00298 namespace internal
00299 {
00300 namespace hopcroft_minimization_undet
00301 {
00302
00303 # define QUOTIENT_TYPES() \
00304 typedef std::list<hstate_t> partition_t; \
00305 typedef std::vector<partition_t> partition_set_t; \
00306 typedef typename partition_t::iterator partition_iterator; \
00307 typedef std::vector<unsigned> class_of_t; \
00308 typedef std::set<hstate_t> delta_ret_t; \
00309 typedef std::pair<unsigned, letter_t> pair_t; \
00310 typedef std::list<pair_t> to_treat_t;
00311
00312 template <typename input_t>
00313 class quotient_splitter
00314 {
00315 public:
00316 AUTOMATON_TYPES(input_t);
00317 AUTOMATON_FREEMONOID_TYPES(input_t);
00318 QUOTIENT_TYPES();
00319
00320 typedef std::vector<bool> going_in_t;
00321
00322 quotient_splitter (const automaton_t& input, class_of_t& class_of,
00323 unsigned max_states)
00324 : input_(input),
00325 alphabet_(input.series().monoid().alphabet()),
00326 class_(class_of),
00327 count_for_(max_states, 0),
00328 twin_(max_states, 0),
00329 going_in_(max_states, false)
00330 { }
00331
00333 bool compute_going_in_states (partition_t& p, letter_t a)
00334 {
00335 for_all_(going_in_t, s, going_in_)
00336 *s = false;
00337
00338 for_all_(partition_t, s, p)
00339 input_.letter_rdeltaf(*this, *s, a, delta_kind::states());
00340 return !met_class_.empty();
00341 }
00342
00344 void operator() (hstate_t s)
00345 {
00346 if (!going_in_[s])
00347 {
00348 going_in_[s] = true;
00349 const unsigned i = class_[s];
00350 if (count_for_[i] == 0)
00351 met_class_.push_back(i);
00352 count_for_[i]++;
00353 }
00354 }
00355
00357 void split (partition_set_t& parts, unsigned& max_partitions)
00358 {
00359 for_all_(std::list<unsigned>, klass, met_class_)
00360 {
00361
00362 if (count_for_[*klass] == parts[*klass].size())
00363 continue;
00364
00365 if (twin_[*klass] == 0)
00366 twin_[*klass] = max_partitions++;
00367 unsigned new_klass = twin_[*klass];
00368
00369 typename partition_t::iterator q;
00370 for (typename partition_t::iterator next = parts[*klass].begin();
00371 next != parts[*klass].end();)
00372 {
00373 q = next;
00374 ++next;
00375 if (going_in_[*q])
00376 {
00377 parts[new_klass].insert(parts[new_klass].end(), *q);
00378 class_[*q] = new_klass;
00379 parts[*klass].erase(q);
00380 }
00381 }
00382 }
00383 }
00384
00385 void add_new_partitions(to_treat_t& to_treat,
00386 const partition_set_t& part)
00387 {
00388 for_all_(std::list<unsigned>, klass, met_class_)
00389 {
00390 if (twin_[*klass] != 0)
00391 {
00392 for_all_const_letters(e, alphabet_)
00393 {
00394 if (find(to_treat.begin(), to_treat.end(), pair_t(*klass, *e)) !=
00395 to_treat.end())
00396 to_treat.push_back(pair_t(twin_[*klass], *e));
00397 else
00398 if (part[*klass].size() < part[twin_[*klass]].size())
00399 to_treat.push_back(pair_t(*klass, *e));
00400 else
00401 to_treat.push_back(pair_t(twin_[*klass], *e));
00402 }
00403 }
00404 }
00405
00406 for_all_(std::list<unsigned>, klass, met_class_)
00407 {
00408 count_for_[*klass] = 0;
00409 twin_[*klass] = 0;
00410 }
00411 met_class_.clear();
00412 }
00413
00414 private:
00415 const automaton_t& input_;
00416 const alphabet_t& alphabet_;
00417 class_of_t& class_;
00418 std::vector<unsigned> count_for_;
00419 std::vector<unsigned> twin_;
00420 going_in_t going_in_;
00421 std::list<unsigned> met_class_;
00422 };
00423 }
00424 }
00425
00426 template <typename A, typename input_t, typename output_t>
00427 void
00428 do_quotient(const AutomataBase<A>&,
00429 const algebra::NumericalSemiring&,
00430 SELECTOR(bool),
00431 output_t& output,
00432 const input_t& input)
00433 {
00434 AUTOMATON_TYPES(input_t);
00435 AUTOMATON_FREEMONOID_TYPES(input_t);
00436 QUOTIENT_TYPES();
00437
00438 using namespace internal::hopcroft_minimization_undet;
00439
00440 const alphabet_t& alphabet_(input.series().monoid().alphabet());
00441 unsigned max_states = 0;
00442
00443 for_all_const_states(i, input)
00444 max_states = std::max(unsigned(*i), max_states);
00445 ++max_states;
00446
00447
00448
00449
00450 unsigned max_partitions = 0;
00451
00452
00453
00454
00455 class_of_t class_(max_states);
00456 partition_set_t part(max_states);
00457
00458
00459
00460
00461 to_treat_t to_treat;
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473 unsigned final = 1;
00474
00475 for_all_const_states (p, input)
00476 {
00477 unsigned c;
00478 if (max_partitions == 0)
00479 {
00480 c = 0;
00481 final = !input.is_final(*p);
00482 }
00483 else
00484 {
00485 c = input.is_final(*p) ? final : (1 - final);
00486 }
00487 class_[*p] = c;
00488 part[c].insert(part[c].end(), *p);
00489 max_partitions = std::max(max_partitions, c + 1);
00490 }
00491
00492
00493
00494
00495
00496 if (max_partitions > 0)
00497 for_all_const_letters (e, alphabet_)
00498 to_treat.push_back(pair_t(0, *e));
00499
00500 if (max_partitions > 1)
00501 for_all_const_letters (e, alphabet_)
00502 to_treat.push_back(pair_t(1, *e));
00503
00504
00505
00506
00507 {
00508 quotient_splitter<input_t> splitter(input, class_, max_states);
00509 while (!to_treat.empty())
00510 {
00511 pair_t c = to_treat.front();
00512 to_treat.pop_front();
00513 unsigned p = c.first;
00514 letter_t a = c.second;
00515
00516 if (!splitter.compute_going_in_states(part[p], a))
00517 continue;
00518 splitter.split(part, max_partitions);
00519
00520 splitter.add_new_partitions(to_treat, part);
00521 }
00522 }
00523
00524
00525
00526
00527
00528 for (unsigned i = 0; i < max_partitions; ++i)
00529 output.add_state();
00530
00531 delta_ret_t delta_ret;
00532 std::set<unsigned> already_linked;
00533 for (unsigned i = 0; i < max_partitions; ++i)
00534 {
00535
00536
00537 hstate_t s = part[i].front();
00538
00539 if (input.is_final(s))
00540 output.set_final(i);
00541
00542
00543 for_all_const_letters (e, alphabet_)
00544 {
00545 delta_ret.clear();
00546 already_linked.clear();
00547
00548 input.letter_deltac(delta_ret, s, *e, delta_kind::states());
00549 for_all_(delta_ret_t, out, delta_ret)
00550 {
00551 unsigned c = class_[*out];
00552 if (already_linked.find(c) == already_linked.end())
00553 {
00554 already_linked.insert(c);
00555 output.add_letter_transition(i, c, *e);
00556 }
00557 }
00558 }
00559 }
00560
00561
00562 for_all_const_initial_states(i, input)
00563 output.set_initial(class_[*i]);
00564 }
00565
00566 # undef QUOTIENT_TYPES
00567
00568
00569
00570
00571
00572
00573 template <class S, class T,
00574 typename A, typename input_t, typename output_t>
00575 void
00576 do_quotient(const AutomataBase<A>& ,
00577 const S& ,
00578 const T& ,
00579 output_t& output,
00580 const input_t& input)
00581 {
00582 AUTOMATON_TYPES(input_t);
00583 AUTOMATON_FREEMONOID_TYPES(input_t);
00584 using namespace std;
00585
00586
00587
00588
00589
00590 typedef set<htransition_t> set_transitions_t;
00591 typedef set<hstate_t> set_states_t;
00592 typedef set<semiring_elt_t> set_semiring_elt_t;
00593 typedef vector<semiring_elt_t> vector_semiring_elt_t;
00594 typedef pair<unsigned, letter_t> pair_class_letter_t;
00595 typedef pair<hstate_t, semiring_elt_t> pair_state_semiring_elt_t;
00596 typedef set<pair_state_semiring_elt_t> set_pair_state_semiring_elt_t;
00597 typedef map<semiring_elt_t, unsigned> map_semiring_elt_t;
00598
00599 series_set_elt_t null_series = input.series().zero_;
00600 semiring_elt_t weight_zero = input.series().semiring().wzero_;
00601 monoid_elt_t monoid_identity = input.series().monoid().VCSN_EMPTY_;
00602 const alphabet_t& alphabet (input.series().monoid().alphabet());
00603
00604 queue<pair_class_letter_t> the_queue;
00605
00606 set<unsigned> met_classes;
00607 set_transitions_t transitions_leaving;
00608
00609 unsigned max_partition = 0;
00610
00611 unsigned max_states = 0;
00612
00613 for_all_const_states(q, input)
00614 max_states = std::max(unsigned (*q), max_states);
00615 ++max_states;
00616
00617 max_states = std::max(max_states, 2u);
00618
00619 vector< vector<set_pair_state_semiring_elt_t> > inverse (max_states);
00620
00621 map<letter_t, unsigned> pos_of_letter;
00622 {
00623 unsigned pos (0);
00624
00625 for_all_const_letters(a, alphabet)
00626 pos_of_letter[*a] = pos++;
00627 }
00628
00629 set_states_t states_visited;
00630 set_semiring_elt_t semiring_had_class;
00631 vector<set_states_t> classes (max_states);
00632 vector<unsigned> class_of_state (max_states);
00633 vector_semiring_elt_t old_weight (max_states);
00634 map_semiring_elt_t class_of_weight;
00635
00636 for (unsigned i = 0; i < max_states; ++i)
00637 inverse[i].resize(max_states);
00638
00639 for_all_const_states(q, input)
00640 for_all_const_letters(a, alphabet)
00641 {
00642
00643 for_all_const_(set_states_t, r, states_visited)
00644 old_weight[*r] = weight_zero;
00645 states_visited.clear();
00646
00647 set_transitions_t transitions_comming;
00648 input.letter_rdeltac(transitions_comming, *q, *a,
00649 delta_kind::transitions());
00650
00651 for_all_const_(set_transitions_t, e, transitions_comming)
00652 {
00653 hstate_t p = input.src_of(*e);
00654 if (states_visited.find(p) != states_visited.end())
00655 inverse[*q][pos_of_letter[*a]].
00656 erase(pair_state_semiring_elt_t (p, old_weight[p]));
00657 else
00658 states_visited.insert(p);
00659 series_set_elt_t sd = input.series_of(*e);
00660 monoid_elt_t md (input.structure().series().monoid(), *a);
00661 semiring_elt_t wsd = sd.get(md);
00662 old_weight[p] += wsd;
00663 inverse[*q][pos_of_letter[*a]].
00664 insert(pair_state_semiring_elt_t (p, old_weight[p]));
00665 }
00666 }
00667
00668
00669
00670
00671
00672
00673 bool empty = true;
00674 unsigned class_non_final (0);
00675
00676 for_all_const_states(q, input)
00677 {
00678 if (not input.is_final(*q))
00679 {
00680 if (empty == true)
00681 {
00682 empty = false;
00683 class_non_final = max_partition;
00684 max_partition++;
00685 }
00686 classes[class_non_final].insert(*q);
00687 class_of_state[*q] = class_non_final;
00688 }
00689 else
00690 {
00691 semiring_elt_t w = input.get_final(*q).get(monoid_identity);
00692 if (semiring_had_class.find(w) == semiring_had_class.end())
00693 {
00694 semiring_had_class.insert(w);
00695 classes[max_partition].insert(*q);
00696 class_of_weight[w] = max_partition;
00697 class_of_state[*q] = max_partition;
00698 max_partition++;
00699 }
00700 else
00701 {
00702 classes[class_of_weight[w]].insert(*q);
00703 class_of_state[*q] = class_of_weight[w];
00704 }
00705 }
00706 }
00707
00708
00709
00710
00711
00712 for (unsigned i = 0; i < max_partition; i++)
00713 for_all_const_letters(a, alphabet)
00714 the_queue.push(pair_class_letter_t (i, *a));
00715
00716
00717
00718
00719
00720 unsigned old_max_partition = max_partition;
00721
00722 while(not the_queue.empty())
00723 {
00724 pair_class_letter_t pair = the_queue.front();
00725 the_queue.pop();
00726
00727 met_classes.clear();
00728 vector_semiring_elt_t val (max_states);
00729
00730 for_all_const_states(q, input)
00731 val[*q] = 0;
00732
00733
00734 for_all_const_(set_states_t, q, classes[pair.first])
00735 for_all_const_(set_pair_state_semiring_elt_t, pair_,
00736 inverse[*q][pos_of_letter[pair.second]])
00737 {
00738 unsigned state = pair_->first;
00739 if (met_classes.find(class_of_state[state]) ==
00740 met_classes.end())
00741 met_classes.insert(class_of_state[state]);
00742 val[state] += pair_->second;
00743 }
00744
00745
00746 for_all_const_(set<unsigned>, class_id, met_classes)
00747 {
00748 if (classes[*class_id].size() == 1)
00749 continue ;
00750
00751 queue<hstate_t> to_erase;
00752 semiring_elt_t next_val;
00753 semiring_elt_t first_val = val[*(classes[*class_id].begin())];
00754 class_of_weight.clear();
00755 semiring_had_class.clear();
00756
00757 for_all_const_(set_states_t, p, classes[*class_id])
00758 {
00759 next_val = val[*p];
00760
00761 if (next_val != first_val)
00762 {
00763 if (semiring_had_class.find(next_val) ==
00764 semiring_had_class.end())
00765 {
00766 classes[max_partition].insert(*p);
00767 class_of_state[*p] = max_partition;
00768 semiring_had_class.insert(next_val);
00769 class_of_weight[next_val] = max_partition;
00770 max_partition++;
00771 }
00772 else
00773 {
00774 classes[class_of_weight[next_val]].insert(*p);
00775 class_of_state[*p] = class_of_weight[next_val];
00776 }
00777 to_erase.push(*p);
00778 }
00779 }
00780
00781 while(not to_erase.empty())
00782 {
00783 hstate_t s = to_erase.front();
00784 to_erase.pop();
00785 classes[*class_id].erase(s);
00786 }
00787
00788
00789 for (unsigned i = old_max_partition; i < max_partition; i++)
00790 for_all_const_letters(b, alphabet)
00791 the_queue.push(pair_class_letter_t(i, *b));
00792 old_max_partition = max_partition;
00793 }
00794 }
00795
00796
00797
00798
00799
00800 typedef vector<series_set_elt_t> vector_series_set_elt_t;
00801
00802 std::vector<hstate_t> out_states (max_partition);
00803
00804
00805
00806
00807
00808 for(unsigned i = 0; i < max_partition; i++)
00809 {
00810 out_states[i] = output.add_state();
00811 hstate_t a_state = *classes[i].begin();
00812 series_set_elt_t a_serie = null_series;
00813
00814 for_all_const_(set_states_t, state, classes[i])
00815 if(input.is_initial(*state))
00816 a_serie += input.get_initial(*state);
00817
00818 output.set_initial(out_states[i] , a_serie);
00819
00820 if (input.is_final(a_state))
00821 output.set_final(out_states[i] , input.get_final(a_state));
00822 }
00823
00824
00825 vector_series_set_elt_t seriesof (max_partition, null_series);
00826
00827 for(unsigned i = 0; i < max_partition; i++)
00828 {
00829 met_classes.clear();
00830
00831 transitions_leaving.clear();
00832 input.deltac(transitions_leaving, *classes[i].begin(),
00833 delta_kind::transitions());
00834
00835 for_all_const_(set_transitions_t, e, transitions_leaving)
00836 {
00837 series_set_elt_t se = input.series_of(*e);
00838 unsigned cs = class_of_state[input.dst_of(*e)];
00839
00840 if (met_classes.find(cs) == met_classes.end())
00841 {
00842 met_classes.insert(cs);
00843 seriesof[cs] = se;
00844 }
00845 else
00846 seriesof[cs] += se;
00847 }
00848
00849 for_all_const_(set<unsigned>, cs, met_classes)
00850 output.add_series_transition(out_states[i],
00851 out_states[*cs],
00852 seriesof[*cs]);
00853 }
00854 }
00855
00856 template<typename A, typename T>
00857 Element<A, T>
00858 quotient(const Element<A, T>& a)
00859 {
00860 TIMER_SCOPED ("quotient");
00861 typedef Element<A, T> auto_t;
00862 AUTOMATON_TYPES(auto_t);
00863 Element<A, T> output(a.structure());
00864 do_quotient(a.structure(), a.structure().series().semiring(),
00865 SELECT(semiring_elt_value_t), output, a);
00866 return output;
00867 }
00868
00869 }
00870
00871 #endif // ! VCSN_ALGORITHMS_MINIMIZATION_HOPCROFT_HXX