- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

# minimization_hopcroft.hxx

    00001 // minimization_hopcroft.hxx: this file is part of the Vaucanson project.
    00002 //
    00003 // Vaucanson, a generic library for finite state machines.
    00004 //
    00005 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The Vaucanson Group.
    00006 //
    00007 // This program is free software; you can redistribute it and/or
    00008 // modify it under the terms of the GNU General Public License
    00009 // as published by the Free Software Foundation; either version 2
    00010 // of the License, or (at your option) any later version.
    00011 //
    00012 // The complete GNU General Public Licence Notice can be found as the
    00013 // `COPYING' file in the root directory.
    00014 //
    00015 // The Vaucanson Group consists of people listed in the `AUTHORS' file.
    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/algorithms/is_deterministic.hh>
    00029 # include <vaucanson/algorithms/complete.hh>
    00030 # include <vaucanson/automata/concept/automata_base.hh>
    00031 # include <vaucanson/misc/usual_macros.hh>
    00032
    00033 # ifndef VCSN_NDEBUG
    00034 #  include <vaucanson/algorithms/is_deterministic.hh>
    00035 # endif // ! VCSN_NDEBUG
    00036
    00037 namespace vcsn
    00038 {
    00039
    00040   namespace internal
    00041   {
    00042     namespace hopcroft_minimization_det
    00043     {
    00044
    00045 # define HOPCROFT_TYPES()                                               \
    00046       typedef std::set<hstate_t> hstates_t;                             \
    00047       typedef std::vector<hstates_t> partition_t;                       \
    00048       typedef std::vector<unsigned> class_of_t;                         \
    00049       typedef std::queue<std::pair<hstates_t*, unsigned> > to_treat_t;
    00050
    00054       template <typename input_t>
    00055       struct splitter_functor
    00056       {
    00057         AUTOMATON_TYPES (input_t);
    00058         AUTOMATON_FREEMONOID_TYPES (input_t);
    00059         HOPCROFT_TYPES ();
    00060
    00061         const input_t& input_;
    00062         hstates_t going_in_;
    00063         class_of_t& class_of_;
    00064         std::list<unsigned> maybe_splittable_;
    00065         std::vector<unsigned> count_for_;
    00066
    00067         splitter_functor (const input_t& input, unsigned int max_state,
    00068                           class_of_t& class_of)
    00069           : input_ (input), going_in_ (), class_of_(class_of),
    00070             count_for_ (max_state)
    00071         {}
    00072
    00074         bool compute_states_going_in (const hstates_t& ss, letter_t l)
    00075         {
    00076           going_in_.clear ();
    00077           maybe_splittable_.clear ();
    00078           for_all_const_ (hstates_t, i, ss)
    00079           {
    00080             for (rdelta_iterator t(input_.value(), *i); ! t.done(); t.next())
    00081             {
    00082               monoid_elt_t w(input_.series_of(*t).structure().monoid(), l);
    00083               if (input_.series_of(*t).get(w) != input_.series().semiring().wzero_)
    00084               {
    00085                 hstate_t s = input_.src_of(*t);
    00086                 unsigned class_of_state = class_of_[s];
    00087
    00088                 if (count_for_[class_of_state] == 0)
    00089                   maybe_splittable_.push_back (class_of_state);
    00090                 count_for_[class_of_state]++;
    00091                 going_in_.insert (s);
    00092               }
    00093             }
    00094           }
    00095           return not going_in_.empty ();
    00096         }
    00097
    00099         void execute (partition_t& partition, to_treat_t& to_treat,
    00100                       unsigned& n_partition)
    00101         {
    00102           for_all (std::list<unsigned>, inpartition, maybe_splittable_)
    00103           {
    00104             hstates_t& states = partition[*inpartition];
    00105             if (states.size () == count_for_[*inpartition])
    00106             { // All elements in states are predecessors, no split.
    00107               count_for_[*inpartition] = 0;
    00108               continue;
    00109             }
    00110             count_for_[*inpartition] = 0;
    00111             hstates_t states_inter_going_in;
    00112             hstates_t& states_minus_going_in = partition[n_partition];
    00113             // Compute @a states \ @a going_in_.
    00114             set_difference
    00115               (states.begin (), states.end (),
    00116                going_in_.begin (), going_in_.end (),
    00117                std::insert_iterator<hstates_t> (states_minus_going_in,
    00118                                                 states_minus_going_in.begin ()));
    00119             // Compute @a states Inter @a going_in_.
    00120             set_intersection
    00121               (states.begin(), states.end (),
    00122                going_in_.begin (), going_in_.end (),
    00123                std::insert_iterator<hstates_t> (states_inter_going_in,
    00124                                                 states_inter_going_in.begin ()));
    00125             // A split MUST occur.
    00126             assertion (not (states_inter_going_in.empty ()
    00127                             or states_minus_going_in.empty ()));
    00128             // @a states must be the bigger one.
    00129             if (states_minus_going_in.size () > states_inter_going_in.size ())
    00130             {
    00131               states.swap (states_minus_going_in);
    00132               states_minus_going_in.swap (states_inter_going_in);
    00133             }
    00134             else
    00135               states.swap (states_inter_going_in);
    00136             for_all_const_ (hstates_t, istate, states_minus_going_in)
    00137               class_of_[*istate] = n_partition;
    00138             to_treat.push (std::make_pair (&states_minus_going_in,
    00139                                            n_partition++));
    00140           }
    00141         }
    00142       };
    00143
    00145       template <typename input_t, typename output_t>
    00146       struct transition_adder_functor
    00147       {
    00148         AUTOMATON_TYPES (input_t);
    00149         HOPCROFT_TYPES ();
    00150
    00151         const input_t& input_;
    00152         output_t& output_;
    00153         const class_of_t& class_of_;
    00154
    00155         unsigned src_;
    00156
    00157         transition_adder_functor (const input_t& input, output_t& output,
    00158                                   const class_of_t& class_of)
    00159           : input_ (input), output_ (output), class_of_ (class_of)
    00160         {}
    00161
    00163         void execute (hstate_t representative)
    00164         {
    00165           src_ = class_of_[representative];
    00166           for (delta_iterator t(input_.value(), representative); ! t.done(); t.next())
    00167           {
    00168             output_.add_series_transition (src_, class_of_[input_.dst_of (*t)],
    00169                                            input_.series_of (*t));
    00170           }
    00171         }
    00172       };
    00173     }
    00174   }
    00175
    00176
    00177   template <typename A, typename AI1, typename AI2>
    00178   void
    00179   do_hopcroft_minimization_det(const AutomataBase<A>&,
    00180                                Element<A, AI2>&         output,
    00181                                const Element<A, AI1>&   input)
    00182   {
    00183     typedef Element<A, AI1> input_t;
    00184     typedef Element<A, AI2> output_t;
    00185     AUTOMATON_TYPES (input_t);
    00186     AUTOMATON_FREEMONOID_TYPES (input_t);
    00187     HOPCROFT_TYPES ();
    00188
    00189     using namespace internal::hopcroft_minimization_det;
    00190
    00191     precondition(is_deterministic(input));
    00192
    00193     unsigned max_state = input.states ().back () + 1;
    00194     partition_t partition (max_state);
    00195     class_of_t class_of (max_state);
    00196     to_treat_t to_treat;
    00197     unsigned n_partition = 0;
    00198     const alphabet_t& alphabet =
    00199       input.structure ().series ().monoid ().alphabet ();
    00200
    00201     {
    00202       // Initialize Partition = {Q \ F , F }
    00203       hstates_t* finals = 0, * others = 0;
    00204       int n_finals = -1, n_others = -1,
    00205         count_finals = 0, count_others = 0;
    00206
    00207 # define add_to_class(Name)                     \
    00208       do {                                      \
    00209         if (not Name)                           \
    00210         {                                       \
    00211           Name = &(partition[n_partition]);     \
    00212           n_ ## Name = n_partition++;           \
    00213         }                                       \
    00214         count_ ## Name ++;                      \
    00215         (*Name).insert (*state);                \
    00216         class_of[*state] = n_ ## Name;          \
    00217       } while (0)
    00218
    00219       for_all_const_states (state, input)
    00220         if (input.is_final (*state))
    00221           add_to_class (finals);
    00222         else
    00223           add_to_class (others);
    00224 # undef add_to_class
    00225
    00226       if (n_partition == 0)
    00227         return;
    00228       if (n_partition == 1)
    00229       {
    00230         output = input;
    00231         return;
    00232       }
    00233       // Put F or Q \ F in the "To treat" list T.
    00234       if (count_finals > count_others)
    00235         to_treat.push (std::make_pair (others, n_others));
    00236       else
    00237         to_treat.push (std::make_pair (finals, n_finals));
    00238     }
    00239
    00240     {
    00241       splitter_functor<input_t> splitter (input, max_state, class_of);
    00242
    00243       // While T is not empty,
    00244       while (not to_treat.empty () && n_partition < max_state)
    00245       {
    00246         // Remove a set S of T ,
    00247         hstates_t& states = *(to_treat.front ().first);
    00248         to_treat.pop ();
    00249
    00250         // For each letter l in Alphabet,
    00251         for_all_const_letters (letter, alphabet)
    00252           {
    00253             if (not splitter.compute_states_going_in (states, *letter))
    00254               continue;
    00255             splitter.execute (partition, to_treat, n_partition);
    00256             if (n_partition == max_state)
    00257               break;
    00258           }
    00259       }
    00260     }
    00261
    00262     // Build the automaton.
    00263     // Assume that states are numbers starting from 0.
    00264     for (unsigned i = 0; i < n_partition; ++i)
    00265       output.add_state ();
    00266
    00267     transition_adder_functor<input_t, output_t>
    00268       transition_adder (input, output, class_of);
    00269
    00270     typename partition_t::iterator istates = partition.begin ();
    00271     for (unsigned i = 0; i < n_partition; ++i, ++istates)
    00272     {
    00273       hstate_t representative = *(*istates).begin();
    00274
    00275       if (input.is_final (representative))
    00276         output.set_final (class_of[representative]);
    00277       transition_adder.execute (representative);
    00278     }
    00279
    00280     for_all_const_initial_states (state, input)
    00281       output.set_initial (class_of[*state]);
    00282   }
    00283
    00284 # undef HOPCROFT_TYPES
    00285
    00295   template<typename A, typename AI>
    00296   Element<A, AI>
    00297   minimization_hopcroft(const Element<A, AI>& a)
    00298   {
    00299     BENCH_TASK_SCOPED("minimization_hopcroft");
    00300     precondition(is_deterministic(a));
    00301     precondition(is_complete(a));
    00302     Element<A, AI> output(a.structure());
    00303     do_hopcroft_minimization_det(a.structure(), output, a);
    00304     return output;
    00305   }
    00306
    00307
    00308   /*-------------------------------------.
    00309   | Quotient with Boolean multiplicities |
    00310   `-------------------------------------*/
    00311   namespace internal
    00312   {
    00313     namespace hopcroft_minimization_undet
    00314     {
    00315
    00316 # define QUOTIENT_TYPES()                                               \
    00317       typedef std::list<hstate_t> partition_t;                          \
    00318       typedef std::vector<partition_t> partition_set_t;                 \
    00319       typedef typename partition_t::iterator partition_iterator;        \
    00320       typedef std::vector<unsigned> class_of_t;                         \
    00321       typedef std::pair<unsigned, letter_t> pair_t;                     \
    00322       typedef std::list<pair_t> to_treat_t;
    00323
    00324       template <typename input_t>
    00325       class quotient_splitter
    00326       {
    00327       public:
    00328         AUTOMATON_TYPES(input_t);
    00329         AUTOMATON_FREEMONOID_TYPES(input_t);
    00330         QUOTIENT_TYPES();
    00331
    00332         typedef std::vector<bool> going_in_t;
    00333
    00334         quotient_splitter (const automaton_t& input, class_of_t& class_of,
    00335                            unsigned max_states)
    00336           : input_(input),
    00337             alphabet_(input.series().monoid().alphabet()),
    00338             class_(class_of),
    00339             count_for_(max_states, 0),
    00340             twin_(max_states, 0),
    00341             going_in_(max_states, false)
    00342         { }
    00343
    00345         bool compute_going_in_states (partition_t& p, letter_t a)
    00346         {
    00347           for_all_(going_in_t, s, going_in_)
    00348             *s = false;
    00349
    00350
    00351           semiring_elt_t weight_zero = input_.series().semiring().wzero_;
    00352           monoid_elt_t w(input_.series().monoid(), a);
    00353
    00354           for_all_(partition_t, s, p)
    00355           {
    00356             for (rdelta_iterator t(input_.value(), *s); ! t.done(); t.next())
    00357             {
    00358               series_set_elt_t st = input_.series_of(*t);
    00359               if (st.get(w) != weight_zero)
    00360               {
    00361                 hstate_t s = input_.src_of(*t);
    00362                 if (!going_in_[s])
    00363                 {
    00365                   going_in_[s] = true;
    00366                   const unsigned i = class_[s];
    00367                   if (count_for_[i] == 0)
    00368                     met_class_.push_back(i);
    00369                   count_for_[i]++;
    00370                 }
    00371               }
    00372             }
    00373           }
    00374           return !met_class_.empty();
    00375         }
    00376
    00378         void split (partition_set_t& parts, unsigned& max_partitions)
    00379         {
    00380           for_all_(std::list<unsigned>, klass, met_class_)
    00381           {
    00382             // if all states are predecessors there is no needed split
    00383             if (count_for_[*klass] == parts[*klass].size())
    00384               continue;
    00385
    00386             if (twin_[*klass] == 0)
    00387               twin_[*klass] = max_partitions++;
    00388             unsigned new_klass = twin_[*klass];
    00389
    00390             typename partition_t::iterator q;
    00391             for (typename partition_t::iterator next = parts[*klass].begin();
    00392                  next != parts[*klass].end();)
    00393             {
    00394               q = next;
    00395               ++next;
    00396               if (going_in_[*q])
    00397               {
    00398                 parts[new_klass].insert(parts[new_klass].end(), *q);
    00399                 class_[*q] = new_klass;
    00400                 parts[*klass].erase(q);
    00401               }
    00402             }
    00403           }
    00404         }
    00405
    00406         void add_new_partitions(to_treat_t&             to_treat,
    00407                                 const partition_set_t&  part)
    00408         {
    00409           for_all_(std::list<unsigned>, klass, met_class_)
    00410           {
    00411             if (twin_[*klass] != 0)
    00412             {
    00413               for_all_const_letters(e, alphabet_)
    00414               {
    00415                 if (find(to_treat.begin(), to_treat.end(), pair_t(*klass, *e)) !=
    00416                     to_treat.end())
    00417                   to_treat.push_back(pair_t(twin_[*klass], *e));
    00418                 else
    00419                   if (part[*klass].size() < part[twin_[*klass]].size())
    00420                     to_treat.push_back(pair_t(*klass, *e));
    00421                   else
    00422                     to_treat.push_back(pair_t(twin_[*klass], *e));
    00423               }
    00424             }
    00425           }
    00426
    00427           for_all_(std::list<unsigned>, klass, met_class_)
    00428           {
    00429             count_for_[*klass] = 0;
    00430             twin_[*klass] = 0;
    00431           }
    00432           met_class_.clear();
    00433         }
    00434
    00435       private:
    00436         const automaton_t& input_;
    00437         const alphabet_t& alphabet_;
    00438         class_of_t& class_;
    00439         std::vector<unsigned> count_for_;
    00440         std::vector<unsigned> twin_;
    00441         going_in_t going_in_;
    00442         std::list<unsigned> met_class_;
    00443       };
    00444     }
    00445   }
    00446
    00447   template <typename A, typename AI1, typename AI2>
    00448   void
    00449   do_quotient(const AutomataBase<A>&,
    00450               const algebra::NumericalSemiring&,
    00451               SELECTOR(bool),
    00452               Element<A, AI2>&          output,
    00453               const Element<A, AI1>&    input)
    00454   {
    00455     BENCH_TASK_SCOPED("do_quotient");
    00456
    00457     typedef Element<A, AI1> input_t;
    00458     typedef Element<A, AI2> output_t;
    00459     AUTOMATON_TYPES(input_t);
    00460     AUTOMATON_FREEMONOID_TYPES(input_t);
    00461     QUOTIENT_TYPES();
    00462
    00463     using namespace internal::hopcroft_minimization_undet;
    00464
    00465     const alphabet_t& alphabet_(input.series().monoid().alphabet());
    00466     unsigned max_states = 0;
    00467
    00468     for_all_const_states(i, input)
    00469       max_states = std::max(unsigned(*i), max_states);
    00470     ++max_states;
    00471
    00472     /*--------------------------.
    00473     | To label the subsets of Q |
    00474     `--------------------------*/
    00475     unsigned max_partitions = 0;
    00476
    00477     /*-----------------------------------------.
    00478     | To manage efficiently the partition of Q |
    00479     `-----------------------------------------*/
    00480     class_of_t          class_(max_states);
    00481     partition_set_t     part(max_states);
    00482
    00483     /*-------------------------.
    00484     | To have a list of (P, a) |
    00485     `-------------------------*/
    00486     to_treat_t          to_treat;
    00487
    00488     /*-------------------------.
    00489     | Initialize the partition |
    00490     `-------------------------*/
    00491     BENCH_TASK_START("initialize partition");
    00492
    00493     // In the general case, we have two sets, part[0] and part[1] One
    00494     // holds the final states, the other the non-final states.  In
    00495     // some cases we may have only one set, for instance if we have no
    00496     // final states, or if we have only final states.  Because we do
    00497     // not want to have an empty part[0], we will fill it with the
    00498     // first kind of state (final / non-final) we encounter.
    00499     unsigned final = 1;
    00500
    00501     for_all_const_states (p, input)
    00502     {
    00503       unsigned c;
    00504       if (max_partitions == 0)
    00505         {
    00506           c = 0;
    00507           final = !input.is_final(*p);
    00508         }
    00509       else
    00510         {
    00511           c = input.is_final(*p) ? final : (1 - final);
    00512         }
    00513       class_[*p] = c;
    00514       part[c].insert(part[c].end(), *p);
    00515       max_partitions = std::max(max_partitions, c + 1);
    00516     }
    00517
    00518     BENCH_TASK_STOP();
    00519
    00520     /*------------------------------.
    00521     | Initialize the list of (P, a) |
    00522     `------------------------------*/
    00523     BENCH_TASK_START("initialize partition");
    00524
    00525     if (max_partitions > 0)
    00526       for_all_const_letters (e, alphabet_)
    00527         to_treat.push_back(pair_t(0, *e));
    00528
    00529     if (max_partitions > 1)
    00530       for_all_const_letters (e, alphabet_)
    00531         to_treat.push_back(pair_t(1, *e));
    00532
    00533     BENCH_TASK_STOP();
    00534
    00535     /*----------.
    00536     | Main loop |
    00537     `----------*/
    00538     BENCH_TASK_START("main loop");
    00539     {
    00540       quotient_splitter<input_t> splitter(input, class_, max_states);
    00541       while (!to_treat.empty())
    00542       {
    00543         BENCH_TASK_SCOPED("inner loop");
    00544         pair_t c = to_treat.front();
    00545         to_treat.pop_front();
    00546         unsigned p = c.first;
    00547         letter_t a = c.second;
    00548
    00549         if (!splitter.compute_going_in_states(part[p], a))
    00550           continue;
    00551         {
    00552           BENCH_TASK_SCOPED("splitter.split");
    00553           splitter.split(part, max_partitions);
    00554         }
    00555         {
    00556           BENCH_TASK_SCOPED("splitter.add_new_partitions");
    00557           splitter.add_new_partitions(to_treat, part);
    00558         }
    00559       }
    00560     }
    00561
    00562     BENCH_TASK_STOP();
    00563
    00564     /*------------------------------------.
    00565     | Construction of the ouput automaton |
    00566     `------------------------------------*/
    00567     BENCH_TASK_START("construct output automaton");
    00568
    00569     // Create the states
    00570     for (unsigned i = 0; i < max_partitions; ++i)
    00571       output.add_state();
    00572
    00573     std::set<unsigned> already_linked;
    00574     for (unsigned i = 0; i < max_partitions; ++i)
    00575     {
    00576       // Get the first state of the partition => each state has the
    00577       // same behaviour
    00578       hstate_t s = part[i].front();
    00579
    00580       if (input.is_final(s))
    00581         output.set_final(i);
    00582
    00583       // Create the transitions
    00584       for_all_const_letters (e, alphabet_)
    00585       {
    00586         already_linked.clear();
    00587
    00588         for (delta_iterator t(input.value(), s); ! t.done(); t.next())
    00589         {
    00590           monoid_elt_t w(input.series_of(*t).structure().monoid(), *e);
    00591           if (input.series_of(*t).get(w) != input.series().semiring().wzero_)
    00592           {
    00593             hstate_t out = input.dst_of(*t);
    00594             unsigned c = class_[out];
    00595             if (already_linked.find(c) == already_linked.end())
    00596             {
    00597               already_linked.insert(c);
    00598               output.add_letter_transition(i, c, *e);
    00599             }
    00600           }
    00601         }
    00602       }
    00603     }
    00604
    00605     // Set initial states.
    00606     for_all_const_initial_states(i, input)
    00607       output.set_initial(class_[*i]);
    00608
    00609     BENCH_TASK_STOP();
    00610   }
    00611
    00612 # undef QUOTIENT_TYPES
    00613
    00614
    00615   /*----------------------------------------.
    00616   | Quotient with multiplicities (covering) |
    00617   `----------------------------------------*/
    00618
    00619   template <class S, class T,
    00620             typename A, typename input_t, typename output_t>
    00621   void
    00622   do_quotient(const AutomataBase<A>&    ,
    00623               const S&                  ,
    00624               const T&                  ,
    00625               output_t&                 output,
    00626               const input_t&            input)
    00627   {
    00628     AUTOMATON_TYPES(input_t);
    00629     AUTOMATON_FREEMONOID_TYPES(input_t);
    00630     using namespace std;
    00631
    00632     /*----------------------------------------.
    00633     | Declare data structures and variables.  |
    00634     `----------------------------------------*/
    00635
    00636     typedef set<htransition_t>                 set_transitions_t;
    00637     typedef set<hstate_t>                      set_states_t;
    00638     typedef set<semiring_elt_t>                set_semiring_elt_t;
    00639     typedef vector<semiring_elt_t>             vector_semiring_elt_t;
    00640     typedef pair<unsigned, letter_t>           pair_class_letter_t;
    00641     typedef pair<hstate_t, semiring_elt_t>     pair_state_semiring_elt_t;
    00642     typedef set<pair_state_semiring_elt_t>     set_pair_state_semiring_elt_t;
    00643     typedef map<semiring_elt_t, unsigned>      map_semiring_elt_t;
    00644
    00645     series_set_elt_t    null_series     = input.series().zero_;
    00646     semiring_elt_t      weight_zero     = input.series().semiring().wzero_;
    00647     monoid_elt_t        monoid_identity = input.series().monoid().VCSN_EMPTY_;
    00648     const alphabet_t&   alphabet (input.series().monoid().alphabet());
    00649
    00650     queue<pair_class_letter_t>                          the_queue;
    00651
    00652     set<unsigned>       met_classes;
    00653
    00654     unsigned    max_partition   = 0;
    00655     unsigned    max_states      = 0;
    00656
    00657     for_all_const_states(q, input)
    00658       max_states = std::max(unsigned (*q), max_states);
    00659     ++max_states;
    00660     // Avoid special case problem (one initial and final state...)
    00661     max_states = std::max(max_states, 2u);
    00662
    00663     vector< vector<set_pair_state_semiring_elt_t> > inverse (max_states);
    00664
    00665     map<letter_t, unsigned> pos_of_letter;
    00666
    00667     unsigned max_pos = 0;
    00668
    00669     for_all_const_letters(a, alphabet)
    00670       pos_of_letter[*a] = max_pos++;
    00671
    00672     set_states_t                states_visited;
    00673     set_semiring_elt_t          semiring_had_class;
    00674     vector<set_states_t>        classes (max_states);
    00675     vector<unsigned>            class_of_state (max_states);
    00676     vector_semiring_elt_t       old_weight (max_states);
    00677     map_semiring_elt_t          class_of_weight;
    00678
    00679     for (unsigned i = 0; i < max_states; ++i)
    00680       inverse[i].resize(max_pos);
    00681
    00682     for_all_const_states(q, input)
    00683       for_all_const_letters(a, alphabet)
    00684       {
    00685
    00686         for_all_const_(set_states_t, r, states_visited)
    00687           old_weight[*r] = weight_zero;
    00688         states_visited.clear();
    00689
    00690         for (rdelta_iterator e(input.value(), *q); ! e.done(); e.next())
    00691         {
    00692           monoid_elt_t w(input.series_of(*e).structure().monoid(), *a);
    00693           if (input.series_of(*e).get(w) != input.series().semiring().wzero_)
    00694           {
    00695             hstate_t            p = input.src_of(*e);
    00696             if (states_visited.find(p) != states_visited.end())
    00697               inverse[*q][pos_of_letter[*a]].
    00698                 erase(pair_state_semiring_elt_t (p, old_weight[p]));
    00699             else
    00700               states_visited.insert(p);
    00701             series_set_elt_t    sd = input.series_of(*e);
    00702             monoid_elt_t        md (input.structure().series().monoid(), *a);
    00703             semiring_elt_t      wsd = sd.get(md);
    00704             old_weight[p] += wsd;
    00705             inverse[*q][pos_of_letter[*a]].
    00706               insert(pair_state_semiring_elt_t (p, old_weight[p]));
    00707           }
    00708         }
    00709       }
    00710
    00711     /*-----------------------------------------------------------.
    00712     | Initialize the partition with as many classes as there are |
    00713     | final values.                                              |
    00714     `-----------------------------------------------------------*/
    00715
    00716     bool         empty = true;
    00717     unsigned     class_non_final (0);
    00718
    00719     for_all_const_states(q, input)
    00720       {
    00721         if (not input.is_final(*q))
    00722         {
    00723           if (empty == true)
    00724           {
    00725             empty = false;
    00726             class_non_final = max_partition;
    00727             max_partition++;
    00728           }
    00729           classes[class_non_final].insert(*q);
    00730           class_of_state[*q] = class_non_final;
    00731         }
    00732         else
    00733         {
    00734           semiring_elt_t w = input.get_final(*q).get(monoid_identity);
    00735           if (semiring_had_class.find(w) == semiring_had_class.end())
    00736           {
    00737             semiring_had_class.insert(w);
    00738             classes[max_partition].insert(*q);
    00739             class_of_weight[w] = max_partition;
    00740             class_of_state[*q] = max_partition;
    00741             max_partition++;
    00742           }
    00743           else
    00744           {
    00745             classes[class_of_weight[w]].insert(*q);
    00746             class_of_state[*q] = class_of_weight[w];
    00747           }
    00748         }
    00749       }
    00750
    00751     /*-----------------------------------------------------.
    00752     | Initialize the queue with pairs <class_id, letter>.  |
    00753     `-----------------------------------------------------*/
    00754
    00755     for (unsigned i = 0; i < max_partition; i++)
    00756       for_all_const_letters(a, alphabet)
    00757         the_queue.push(pair_class_letter_t (i, *a));
    00758
    00759     /*----------------.
    00760     | The main loop.  |
    00761     `----------------*/
    00762
    00763     unsigned old_max_partition = max_partition;
    00764
    00765     while(not the_queue.empty())
    00766     {
    00767       pair_class_letter_t pair = the_queue.front();
    00768       the_queue.pop();
    00769       met_classes.clear();
    00770       vector_semiring_elt_t val (max_states);
    00771
    00772       // FIXME: Isn't there an easier way to do this?
    00773       for_all_const_states(q, input)
    00774         val[*q] = 0;
    00775
    00776       // First, calculate val[state] and not met_classes.
    00777       for_all_const_(set_states_t, q, classes[pair.first])
    00778         for_all_const_(set_pair_state_semiring_elt_t, pair_,
    00779                        inverse[*q][pos_of_letter[pair.second]])
    00780         {
    00781           unsigned  state = pair_->first;
    00782           if (met_classes.find(class_of_state[state]) ==
    00783               met_classes.end())
    00784             met_classes.insert(class_of_state[state]);
    00785           val[state] += pair_->second;
    00786         }
    00787
    00788       // Next, for each met class, do the partition.
    00789       for_all_const_(set<unsigned>, class_id, met_classes)
    00790       {
    00791         if (classes[*class_id].size() == 1)
    00792           continue ;
    00793
    00794         queue<hstate_t> to_erase;
    00795         semiring_elt_t  next_val;
    00796         semiring_elt_t  first_val = val[*(classes[*class_id].begin())];
    00797         class_of_weight.clear();
    00798         semiring_had_class.clear();
    00799
    00800         for_all_const_(set_states_t, p, classes[*class_id])
    00801         {
    00802           next_val = val[*p];
    00803           // This state must be moved to another class!
    00804           if (next_val != first_val)
    00805           {
    00806             if (semiring_had_class.find(next_val) ==
    00807                 semiring_had_class.end()) // Must create a new class
    00808             {
    00809               classes[max_partition].insert(*p);
    00810               class_of_state[*p] = max_partition;
    00811               semiring_had_class.insert(next_val);
    00812               class_of_weight[next_val] = max_partition;
    00813               max_partition++;
    00814             }
    00815             else
    00816             {
    00817               classes[class_of_weight[next_val]].insert(*p);
    00818               class_of_state[*p] = class_of_weight[next_val];
    00819             }
    00820             to_erase.push(*p);
    00821           }
    00822         }
    00823
    00824         while(not to_erase.empty())
    00825         {
    00826           hstate_t s = to_erase.front();
    00827           to_erase.pop();
    00828           classes[*class_id].erase(s);
    00829         }
    00830
    00831         // Push pairs <new_class_id, letter> into the queue.
    00832         for (unsigned i = old_max_partition; i < max_partition; i++)
    00833           for_all_const_letters(b, alphabet)
    00834             the_queue.push(pair_class_letter_t(i, *b));
    00835         old_max_partition = max_partition;
    00836       }
    00837     }
    00838
    00839     /*------------------.
    00840     | Form the output.  |
    00841     `------------------*/
    00842
    00843     typedef vector<series_set_elt_t> vector_series_set_elt_t;
    00844
    00845     std::vector<hstate_t>       out_states (max_partition);
    00846
    00847     // Add states.
    00848     for(unsigned i = 0; i < max_partition; i++)
    00849     {
    00850       out_states[i]  = output.add_state();
    00851       hstate_t a_state = *classes[i].begin();
    00852       series_set_elt_t a_serie = null_series;
    00853
    00854       for_all_const_(set_states_t, state, classes[i])
    00855         if(input.is_initial(*state))
    00856           a_serie += input.get_initial(*state);
    00857
    00858       output.set_initial(out_states[i] , a_serie);
    00859
    00860       if (input.is_final(a_state))
    00861         output.set_final(out_states[i] , input.get_final(a_state));
    00862     }
    00863
    00864     // Add transitions.
    00865     vector_series_set_elt_t seriesof (max_partition, null_series);
    00866
    00867     for(unsigned i = 0; i < max_partition; i++)
    00868     {
    00869       met_classes.clear();
    00870
    00871       for (delta_iterator e(input.value(), *classes[i].begin()); ! e.done(); e.next())
    00872         {
    00873           series_set_elt_t      se = input.series_of(*e);
    00874           unsigned              cs = class_of_state[input.dst_of(*e)];
    00875
    00876           if (met_classes.find(cs) == met_classes.end())
    00877           {
    00878             met_classes.insert(cs);
    00879             seriesof[cs] = se;
    00880           }
    00881           else
    00882             seriesof[cs] += se;
    00883         }
    00884
    00885       for_all_const_(set<unsigned>, cs, met_classes)
    00886         if (seriesof[*cs] != null_series)
    00887           output.add_series_transition(out_states[i],
    00888                                        out_states[*cs],
    00889                                        seriesof[*cs]);
    00890     }
    00891   }
    00892
    00893   template<typename A, typename AI>
    00894   Element<A, AI>
    00895   quotient(const Element<A, AI>& a)
    00896   {
    00897     BENCH_TASK_SCOPED("quotient");
    00898     precondition(is_realtime(a));
    00899     typedef Element<A, AI> automaton_t;
    00900     AUTOMATON_TYPES(automaton_t);
    00901     automaton_t output(a.structure());
    00902     do_quotient(a.structure(), a.structure().series().semiring(),
    00903                 SELECT(semiring_elt_value_t), output, a);
    00904     return output;
    00905   }
    00906
    00907 } // vcsn
    00908
    00909 #endif // ! VCSN_ALGORITHMS_MINIMIZATION_HOPCROFT_HXX