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

- File List
- File Members

# reduce.hxx

    00001 // reduce.hxx: this file is part of the Vaucanson project.
    00002 //
    00003 // Vaucanson, a generic library for finite state machines.
    00004 //
    00005 // Copyright (C) 2008, 2011 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
    00018 #ifndef VCSN_ALGORITHMS_REDUCE_HXX
    00019 # define VCSN_ALGORITHMS_REDUCE_HXX
    00020 # include <queue>
    00021 # include <vector>
    00022 # include <map>
    00023 # include <vaucanson/misc/usual_macros.hh>
    00024
    00025 namespace vcsn {
    00026
    00027   template<typename A, typename AI, typename AO>
    00028   class reducer
    00029   {
    00030     typedef Element<A, AI> Auto;
    00031     AUTOMATON_TYPES(Auto);
    00032     AUTOMATON_FREEMONOID_TYPES(Auto);
    00033     typedef std::vector<semiring_elt_t> semiring_vector_t;
    00034     typedef std::vector<std::map<std::size_t, semiring_elt_t> > semiring_matrix_t;
    00035     typedef std::map<monoid_elt_t, semiring_matrix_t> semiring_matrix_set_t;
    00036
    00037   /* output may have an implementation different from the
    00038      implementation of the input; this is for instance the case where
    00039      input is a transpose view, as in the wrappers.
    00040      */
    00041
    00042   public:
    00043     reducer(const Element<A, AI>& input, Element<A, AO>& output) :
    00044       zero(input.series().semiring().wzero_),
    00045       one(input.series().semiring().wone_),
    00046       empty_word(input.series().monoid().VCSN_EMPTY_),
    00047       output(output)
    00048     {
    00049       std::map<hstate_t, int>   state_to_index;
    00050       int i = 0;
    00051
    00052       for_all_const_states(s, input)
    00053         state_to_index[*s] = i++;
    00054       nb_states = i;
    00055
    00056       init.resize(i);
    00057       final.resize(i);
    00058
    00059       // We assume that there are only weights on initial and final
    00060       // transitions
    00061
    00062       // Conversion of the automaton into linear representation
    00063       for_all_const_initial_states(s, input)
    00064         init[state_to_index[*s]] = input.get_initial(*s).get(empty_word);
    00065
    00066       for_all_const_final_states(s, input)
    00067         final[state_to_index[*s]] = input.get_final(*s).get(empty_word);
    00068
    00069       for_all_const_transitions(t, input)
    00070       {
    00071         series_set_elt_t s = input.series_of(*t);
    00072         assert(is_support_in_alphabet(s));
    00073         for_all_(series_set_elt_t::support_t, l, s.supp())
    00074         {
    00075           const monoid_elt_t m(input.structure().series().monoid(), *l);
    00076           typename semiring_matrix_set_t::iterator it = letter_matrix_set.find(m);
    00077           if (it == letter_matrix_set.end())
    00078             it = letter_matrix_set.insert(make_pair(m, semiring_matrix_t(nb_states))).first;
    00079           it->second[state_to_index[input.src_of(*t)]][state_to_index[input.dst_of(*t)]] = s.get(m);
    00080         }
    00081       }
    00082     }
    00083
    00084     //utility class
    00085     struct triple_t
    00086     {
    00087       hstate_t state;
    00088       semiring_vector_t vector;
    00089       monoid_elt_t letter;
    00090
    00091       triple_t(const hstate_t& state, const semiring_vector_t& vector,
    00092                const monoid_elt_t& letter) :
    00093         state(state), vector(vector), letter(letter) {}
    00094
    00095     };
    00096
    00097     //utility methods
    00098     void product_vector_matrix(const semiring_vector_t& v,
    00099                                const semiring_matrix_t& m,
    00100                                semiring_vector_t& res)
    00101     {
    00102       for(int i=0; i<nb_states; i++)
    00103         for(typename std::map<std::size_t, semiring_elt_t>::const_iterator it
    00104               = m[i].begin(); it != m[i].end(); ++it)
    00105           {
    00106             int j = it->first;
    00107             res[j] += v[i] * it->second;
    00108           }
    00109     }
    00110
    00111     semiring_elt_t scalar_product(const semiring_vector_t& v,
    00112                                   const semiring_vector_t& w)
    00113     {
    00114       semiring_elt_t res(zero);
    00115       for(int i = 0; i < nb_states; ++i)
    00116         res += v[i] * w[i];
    00117       return res;
    00118     }
    00119
    00120     //core of the algorithm
    00121     void
    00122     left_reduce()
    00123     {
    00124       //if the initial vector is null, the reduction is empty
    00125       {
    00126         int i;
    00127         for (i = 0; i < nb_states; ++i)
    00128           if (init[i] != zero)
    00129             break;
    00130         if (i == nb_states)
    00131           return;
    00132       }
    00133       // otherwise...
    00134       std::queue<triple_t> queue;
    00135       // The base is a list of vectors, each vector is associated with
    00136       // a state of the output
    00137       std::list<std::pair<hstate_t,semiring_vector_t> > base;
    00138       // The initial vector corresponds to the first state and is the
    00139       // first element of the new base
    00140       hstate_t n_init = output.add_state();
    00141       base.push_back(std::pair<hstate_t,semiring_vector_t>(n_init, init));
    00142       output.set_initial(n_init);
    00143       // Final weight of the initial state
    00144       semiring_elt_t t = scalar_product(init, final);
    00145       if(t != zero)
    00146         {
    00147           series_set_elt_t s(output.structure().series());
    00148           s.assoc(empty_word, t);
    00149           output.set_final(n_init, s);
    00150         }
    00151       /* for each letter a, I.mu(a) is computed and pushed in the queue
    00152          with the letter a and the state corresponding to I; it allows to
    00153          build the automaton in the same time.
    00154       */
    00155       for (typename semiring_matrix_set_t::const_iterator it
    00156              = letter_matrix_set.begin(); it != letter_matrix_set.end(); ++it)
    00157         {
    00158           semiring_vector_t nv(nb_states);
    00159           product_vector_matrix(init, it->second, nv);
    00160           queue.push(triple_t(n_init, nv, it->first));
    00161         }
    00162       while (!queue.empty())
    00163         {
    00164           triple_t& tr = queue.front();
    00165           //the triple tr is not yet poped, to keep valid references.
    00166           semiring_vector_t& current = tr.vector;
    00167           // first non null indices of current and base vectors.
    00168           std::size_t curr_fnn = 0;
    00169           std::size_t base_fnn = 0;
    00170           for(typename std::list<std::pair<hstate_t,semiring_vector_t> >::iterator it
    00171                 = base.begin(); it!=base.end(); ++it)
    00172           {
    00173             while (curr_fnn < nb_states && current[curr_fnn] == zero)
    00174               ++curr_fnn;
    00175             // first non null index of the base vector
    00176             // As the matrix is "in stairs" the base_fnn is larger than the previous one
    00177             semiring_vector_t& vbase = it->second;
    00178             while (base_fnn < nb_states && vbase[base_fnn] == zero)
    00179               ++base_fnn;
    00180             // Case A
    00181             if (base_fnn < curr_fnn)
    00182               // nothing to do in this case
    00183               continue;
    00184             // Case B
    00185             if (base_fnn > curr_fnn)
    00186               // current is added to the base before the current base vector
    00187               {
    00188                 hstate_t n_state= output.add_state();
    00189                 base.insert(it,std::pair<hstate_t,semiring_vector_t>(n_state,
    00190                                                                      current));
    00191                 series_set_elt_t s(output.structure().series());
    00192                 s.assoc(tr.letter, one);
    00193                 output.add_series_transition(tr.state, n_state, s);
    00194                 semiring_elt_t t=scalar_product(current, final);
    00195                 if(t != zero)
    00196                 {
    00197                   series_set_elt_t s(output.structure().series());
    00198                   s.assoc(empty_word, t);
    00199                   output.set_final(n_state, s);
    00200                 }
    00201                 // All the vectors current.mu(a) are put in the queue
    00202                 for (typename semiring_matrix_set_t::const_iterator itm
    00203                        = letter_matrix_set.begin();
    00204                      itm != letter_matrix_set.end(); ++itm)
    00205                {
    00206                   semiring_vector_t nv(nb_states);
    00207                   product_vector_matrix(current, itm->second, nv);
    00208                   queue.push(triple_t(n_state, nv, itm->first));
    00209                }
    00210                 // To avoid treatment after exiting the loop:
    00211                 curr_fnn = nb_states;
    00212                 break;
    00213               }
    00214             // Case C
    00215             // Otherwise, current is reduced w.r.t base
    00216             semiring_elt_t ratio = current[curr_fnn] / vbase[curr_fnn];
    00217             // This is safer than current[curr_fnn] = current[curr_fnn]-ratio*vbase[curr_fnn];
    00218             current[curr_fnn] = zero;
    00219             for(int i = curr_fnn+1; i < nb_states; ++i)
    00220                 current[i ] =current[i] - ratio*vbase[i];
    00221                 series_set_elt_t s(output.structure().series());
    00222                 s.assoc(tr.letter, ratio);
    00223             output.add_series_transition(tr.state, it->first, s);
    00224           }
    00225           // If current has not been totally reduced w.r.t the base,
    00226           // it has to be put itself in the base
    00227           while (curr_fnn < nb_states && current[curr_fnn] == zero)
    00228             ++curr_fnn;
    00229           if (nb_states> curr_fnn)
    00230             // current is added at the end of the base
    00231             {
    00232               hstate_t n_state= output.add_state();
    00233               base.push_back(std::pair<hstate_t,semiring_vector_t>(n_state,
    00234                                                                    current));
    00235               series_set_elt_t s(output.structure().series());
    00236               s.assoc(tr.letter, one);
    00237               output.add_series_transition(tr.state, n_state, s);
    00238               semiring_elt_t t=scalar_product(current, final);
    00239               if(t != zero)
    00240                 {
    00241                   series_set_elt_t s(output.structure().series());
    00242                   s.assoc(empty_word, t);
    00243                   output.set_final(n_state, s);
    00244                 }
    00245               for (typename semiring_matrix_set_t::const_iterator itm
    00246                      = letter_matrix_set.begin();
    00247                    itm != letter_matrix_set.end(); ++itm)
    00248               {
    00249                 semiring_vector_t nv(nb_states);
    00250                 product_vector_matrix(current, itm->second, nv);
    00251                 queue.push(triple_t(n_state, nv, itm->first));
    00252               }
    00253            }
    00254           queue.pop();
    00255         }
    00256         /* Print the base
    00257           for(typename std::list<std::pair<hstate_t,semiring_vector_t> >::iterator it = base.begin(); it!=base.end(); ++it)
    00258           {
    00259                 std::cerr << it->first << ':';
    00260                 for(int i=0; i < nb_states; ++i)
    00261                         std::cerr << (it->second)[i] << ',';
    00262                 std::cerr << std::endl;
    00263           }
    00264           */
    00265     }
    00266
    00267   private:
    00268     // zero and identity of used algebraic structure.
    00269     semiring_elt_t      zero;
    00270     semiring_elt_t      one;
    00271     monoid_elt_t        empty_word;
    00272
    00273     // Linear representation of the input automaton in matrix form
    00274     semiring_vector_t init;
    00275     semiring_vector_t final;
    00276     semiring_matrix_set_t letter_matrix_set;
    00277     size_t nb_states;
    00278
    00279     Element<A, AO>& output;
    00280   };
    00281
    00282   template<typename A, typename AI, typename AO>
    00283   void
    00284   do_semi_reduce(const Element<A, AI>& a, Element<A, AO>& output)
    00285   {
    00286     reducer<A, AI, AO> r(a, output);
    00287     r.left_reduce();
    00288   }
    00289
    00290   template<typename A, typename AI>
    00291   Element<A, AI>
    00292   semi_reduce(const Element<A, AI>& a)
    00293   {
    00294     precondition(is_realtime(a));
    00295     Element<A, AI> output(a.structure());
    00296     do_semi_reduce(a, output);
    00297     return output;
    00298   }
    00299
    00300   template<typename A, typename AI>
    00301   Element<A, AI>
    00302   reduce(const Element<A, AI>& a, misc::direction_type dir)
    00303   {
    00304     precondition(is_realtime(a));
    00305     Element<A, AI> tmp(a.structure());
    00306     Element<A, AI> output(a.structure());
    00307     if (dir == misc::right_left)
    00308     {
    00309       do_semi_reduce(transpose_view(a), tmp);
    00310       do_semi_reduce(transpose_view(tmp), output);
    00311       return output;
    00312     }
    00313     else
    00314     {
    00315       do_semi_reduce(a, tmp);
    00316       do_semi_reduce(transpose_view(tmp), output);
    00317       return transpose(output);
    00318     }
    00319   }
    00320
    00321
    00322 } // vcsn
    00323
    00324 #endif // !VCSN_ALGORITHMS_REDUCE_HXX //