Vaucanson 1.4
infiltration.hxx
00001 // infiltration.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, 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 #ifndef VCSN_ALGORITHMS_INFILTRATION_HXX
00018 # define VCSN_ALGORITHMS_INFILTRATION_HXX
00019 
00020 # include <set>
00021 # include <map>
00022 # include <queue>
00023 # include <stack>
00024 
00025 # include <vaucanson/algorithms/infiltration.hh>
00026 
00027 # ifndef VCSN_NDEBUG
00028 #  include <vaucanson/algorithms/realtime.hh>
00029 # endif // ! VCSN_NDEBUG
00030 
00031 # include <vaucanson/automata/concept/automata_base.hh>
00032 # include <vaucanson/misc/usual_macros.hh>
00033 # include <vaucanson/automata/implementation/geometry.hh>
00034 # include <vaucanson/misc/static.hh>
00035 
00036 namespace vcsn
00037 {
00038 
00039 /*--------------------------------.
00040 | Functor for infiltration algorithm.  |
00041 `--------------------------------*/
00042 template<typename A, typename T, typename U>
00043 class Infiltration
00044 {
00045   public:
00046     typedef AutomataBase<A> structure_t;
00047     typedef Element<A, T> lhs_t;
00048     typedef Element<A, U> rhs_t;
00049     typedef lhs_t           output_t;
00050     typedef std::map<typename output_t::hstate_t,
00051               std::pair<typename lhs_t::hstate_t, typename rhs_t::hstate_t> >
00052                           pair_map_t;
00053 
00054     Infiltration (const structure_t& structure,
00055              const bool use_geometry)
00056       : use_geometry_(use_geometry),
00057         series_(structure.series()),
00058         monoid_(series_.monoid()),
00059         semiring_zero_(series_.semiring().zero(SELECT(semiring_elt_value_t)))
00060     {
00061     }
00062 
00063     // returns the infiltration of @c lhs and @c rhs (and put it also in @c output)
00064     output_t&
00065     operator() (output_t& output,
00066                 const lhs_t& lhs,
00067                 const rhs_t& rhs,
00068                 pair_map_t& m)
00069     {
00070       BENCH_TASK_SCOPED("infiltration");
00071       visited_.clear();
00072 
00073       precondition(is_realtime(lhs));
00074       precondition(is_realtime(rhs));
00075 
00076       this->initialize_queue(output, lhs, rhs, m);
00077 
00078       while (not to_process_.empty())
00079       {
00080         const pair_hstate_t current_pair = to_process_.front();
00081         to_process_.pop();
00082 
00083         const hstate_t lhs_s         = current_pair.first;
00084         const hstate_t rhs_s         = current_pair.second;
00085         const hstate_t current_state = visited_[current_pair];
00086 
00087         output.set_initial(current_state,
00088                            lhs.get_initial(lhs_s) * rhs.get_initial(rhs_s));
00089         output.set_final(current_state,
00090                          lhs.get_final(lhs_s) * rhs.get_final(rhs_s));
00091 
00092         for (typename lhs_t::delta_iterator l(lhs.value(), lhs_s);
00093              ! l.done();
00094              l.next())
00095           for (typename rhs_t::delta_iterator r(rhs.value(), rhs_s);
00096                ! r.done();
00097                r.next())
00098           {
00099             series_set_elt_t    prod_series(series_);
00100 
00101             if (is_product_not_null(lhs, rhs, l, r, prod_series))
00102             {
00103               const pair_hstate_t new_pair(lhs.dst_of(*l), rhs.dst_of(*r));
00104               typename visited_t::const_iterator found = visited_.find(new_pair);
00105 
00106               hstate_t dst;
00107               if (found == visited_.end())
00108               {
00109                 dst = output.add_state();
00110 
00111                 this->add_state_to_process(output, lhs, rhs, m, dst, new_pair);
00112               }
00113               else
00114                 dst = found->second;
00115               output.add_series_transition(current_state, dst, prod_series);
00116             }
00117           }
00118         for (typename lhs_t::delta_iterator l(lhs.value(), lhs_s);
00119              ! l.done();
00120              l.next())
00121         {
00122               const pair_hstate_t new_pair(lhs.dst_of(*l), rhs_s);
00123               typename visited_t::const_iterator found = visited_.find(new_pair);
00124 
00125               hstate_t dst;
00126               if (found == visited_.end())
00127               {
00128                 dst = output.add_state();
00129 
00130                 this->add_state_to_process(output, lhs, rhs, m, dst, new_pair);
00131               }
00132               else
00133                 dst = found->second;
00134               output.add_series_transition(current_state, dst, lhs.series_of(*l));
00135         }
00136         for (typename rhs_t::delta_iterator r(rhs.value(), rhs_s);
00137              ! r.done();
00138              r.next())
00139         {
00140               const pair_hstate_t new_pair(lhs_s, rhs.dst_of(*r));
00141               typename visited_t::const_iterator found = visited_.find(new_pair);
00142 
00143               hstate_t dst;
00144               if (found == visited_.end())
00145               {
00146                 dst = output.add_state();
00147 
00148                 this->add_state_to_process(output, lhs, rhs, m, dst, new_pair);
00149               }
00150               else
00151                 dst = found->second;
00152               output.add_series_transition(current_state, dst, rhs.series_of(*r));
00153         }
00154 
00155       }
00156       merge_transitions(output);
00157       return output;
00158     }
00159 
00160   private:
00161      //merge transitions with the same ends
00162     void merge_transitions(output_t& a)
00163     {
00164       typedef std::map<hstate_t, series_set_elt_t> map_t;
00165       for_all_states(s, a)
00166         {
00167           map_t map;
00168           std::list<htransition_t> transitions;
00169           for (delta_iterator e(a.value(), *s); ! e.done(); e.next())
00170             {
00171               hstate_t target = a.dst_of(*e);
00172               transitions.push_back(*e);
00173               typename map_t::iterator it = map.find(target);
00174               if (it == map.end())
00175                 map.insert(std::pair<hstate_t, series_set_elt_t>(target,
00176                                                                  a.series_of(*e)));
00177               else
00178                 it->second += a.series_of(*e);
00179             }
00180           for_all_(std::list<htransition_t>, e, transitions)
00181             a.del_transition(*e);
00182           for_all_(map_t, it, map)
00183                 if(it->second != a.series().zero_)
00184                     a.add_series_transition(*s, it->first, it->second);
00185         }
00186     }
00187 
00188     // Some little graphic tools
00189     class grphx
00190     {
00191       public:
00192         template <typename Output, typename Lhs, typename Rhs>
00193         static void
00194         setcoordfrom (Output& a,
00195                       const Lhs& lhs,
00196                       const Rhs& rhs,
00197                       const typename Output::hstate_t state,
00198                       const typename Lhs::hstate_t x_state,
00199                       const typename Rhs::hstate_t y_state)
00200         {
00201           typename std::map<typename Lhs::hstate_t,
00202             typename Lhs::geometry_t::coords_t>::const_iterator iter;
00203           typename std::map<typename Rhs::hstate_t,
00204             typename Rhs::geometry_t::coords_t>::const_iterator iter2;
00205           double x = 0, y = 0;
00206 
00207           iter = lhs.geometry().states().find(x_state);
00208           if (iter != lhs.geometry().states().end())
00209             x = iter->second.first;
00210 
00211           iter2 = rhs.geometry().states().find(y_state);
00212           if (iter2 != rhs.geometry().states().end())
00213             y = iter2->second.second;
00214 
00215           a.geometry().states()[state] = std::make_pair(x, y);
00216         }
00217       private:
00218         // Diagonal alignement with a depth-first traversal
00219         template<typename I>
00220         void
00221         align (const I& a)
00222         {
00223           AUTOMATON_TYPES(I);
00224           std::map<hstate_t,bool> visited;
00225           std::stack<hstate_t> stack;
00226 
00227           for_all_const_states(i, a)
00228             {
00229               visited[*i] = false;
00230               // ensure inaccessible states will be visited
00231               stack.push(*i);
00232             }
00233 
00234           for_all_const_initial_states(i, a)
00235             stack.push(*i);
00236 
00237           int x = 0;
00238           while (!stack.empty())
00239           {
00240             hstate_t i = stack.top();
00241             stack.pop();
00242 
00243             if (!visited[i])
00244             {
00245               visited[i] = true;
00246 
00247               a.geometry()[i] = std::make_pair(x, x);
00248               x++;
00249 
00250               for (delta_iterator j(a.value(), i);
00251                    ! j.done();
00252                    j.next())
00253                 stack.push(a.dst_of(*j));
00254             }
00255           }
00256         }
00257 
00258     };
00259     class no_grphx
00260     {
00261       public:
00262         template <typename Output, typename Lhs, typename Rhs>
00263         static void
00264         setcoordfrom (Output& a,
00265                       const Lhs& lhs,
00266                       const Rhs& rhs,
00267                       const typename Output::hstate_t state,
00268                       const typename Lhs::hstate_t x_state,
00269                       const typename Rhs::hstate_t y_state) {};
00270     };
00271 
00272     // useful typedefs
00273     AUTOMATON_TYPES(output_t);
00274 
00275     typedef std::pair<typename lhs_t::hstate_t, typename rhs_t::hstate_t>
00276                                                       pair_hstate_t;
00277     typedef std::list<htransition_t>                    delta_ret_t;
00278     typedef std::map<pair_hstate_t, hstate_t>           visited_t;
00279     typedef typename series_set_elt_t::support_t        support_t;
00280 
00281     // add a @c new_state in the queue
00282     inline void
00283     add_state_to_process (output_t& output,
00284                           const lhs_t& lhs,
00285                           const rhs_t& rhs,
00286                           pair_map_t& m,
00287                           const hstate_t& new_state,
00288                           const pair_hstate_t& new_pair)
00289     {
00290       m[new_state] = new_pair;
00291       visited_[new_pair] = new_state;
00292       to_process_.push(new_pair);
00293 
00294 # define if_(Cond, ThenClause, ElseClause)                      \
00295 misc::static_if_simple<Cond, ThenClause, ElseClause>::t
00296 # define eq_(Type1, Type2)                      \
00297 misc::static_eq<Type1, Type2>::value
00298 # define DECLARE_GEOMETRY(Type) \
00299   typedef geometry<typename Type::hstate_t, typename Type::htransition_t, typename Type::geometry_coords_t> geometry_ ## Type ;
00300 
00301       DECLARE_GEOMETRY(output_t)
00302       DECLARE_GEOMETRY(lhs_t)
00303       DECLARE_GEOMETRY(rhs_t)
00304       if (use_geometry_)
00305         if_(eq_(typename output_t::geometry_t, geometry_output_t)  and \
00306             eq_(typename rhs_t::geometry_t, geometry_rhs_t) and \
00307             eq_(typename lhs_t::geometry_t, geometry_lhs_t),    \
00308             grphx, no_grphx)
00309           ::setcoordfrom(output, lhs, rhs,
00310                          new_state, new_pair.first, new_pair.second);
00311 # undef if_
00312 # undef eq_
00313     }
00314 
00315     // initialize queue with all pairs of intials states from @c lhs and @c rhs
00316     inline void
00317     initialize_queue (output_t& output,
00318                       const lhs_t& lhs,
00319                       const rhs_t& rhs,
00320                       pair_map_t& m)
00321     {
00322       for_all_const_initial_states(lhs_s, lhs)
00323         for_all_const_initial_states(rhs_s, rhs)
00324         {
00325           const pair_hstate_t   new_pair(*lhs_s, *rhs_s);
00326           const hstate_t        new_state = output.add_state();
00327 
00328           this->add_state_to_process(output, lhs, rhs, m, new_state, new_pair);
00329         }
00330     }
00331 
00332     inline bool
00333     is_product_not_null (const lhs_t& lhs,
00334                          const rhs_t& rhs,
00335                          const typename lhs_t::delta_iterator& l,
00336                          const typename rhs_t::delta_iterator& r,
00337                          series_set_elt_t&  prod_series) const
00338     {
00339       const series_set_elt_t    left_series  = lhs.series_of(*l);
00340       const series_set_elt_t    right_series = rhs.series_of(*r);
00341 
00342       bool                      prod_is_not_null = false;
00343       for_all_(support_t, supp, left_series.supp())
00344         {
00345           const monoid_elt_t     supp_elt (monoid_, *supp);
00346           const semiring_elt_t l = left_series.get(supp_elt);
00347           const semiring_elt_t r = right_series.get(supp_elt);
00348           const semiring_elt_t p = l * r;
00349           if (p != semiring_zero_)
00350           {
00351             prod_series.assoc(*supp, p.value());
00352             prod_is_not_null = true;
00353           }
00354         }
00355       return (prod_is_not_null);
00356     }
00357 
00358     // If set to true, <geometry> tags of the result automaton should be filled
00359     const bool  use_geometry_;
00360 
00361     // keep traces of new states created
00362     visited_t                   visited_;
00363     // @c to_process_ stores all states of output that needs are not
00364     std::queue<pair_hstate_t>   to_process_;
00365 
00366     // frequently used objects in computation
00367     const series_set_t& series_;
00368     const monoid_t&             monoid_;
00369     // This variable's type must not be set to a reference.
00370     const semiring_elt_t        semiring_zero_;
00371 };
00372 
00373 /*-----------.
00374 | Wrappers.  |
00375 `-----------*/
00376 
00377 template<typename A, typename T, typename U>
00378 Element<A, T>
00379 infiltration (const Element<A, T>& lhs, const Element<A, U>& rhs,
00380          std::map<typename T::hstate_t,
00381          std::pair<typename T::hstate_t, typename U::hstate_t> >& m,
00382          const bool use_geometry)
00383 {
00384   Element<A, T> ret(rhs.structure());
00385   Infiltration<A, T, U> do_infiltration(ret.structure(), use_geometry);
00386   return do_infiltration (ret, lhs, rhs, m);
00387 }
00388 
00389 template<typename A, typename T, typename U>
00390 Element<A, T>
00391 infiltration (const Element<A, T>& lhs, const Element<A, U>& rhs,
00392          const bool use_geometry)
00393 {
00394   std::map<typename T::hstate_t,
00395     std::pair<typename T::hstate_t, typename U::hstate_t> > m;
00396   return infiltration (lhs, rhs, m, use_geometry);
00397 }
00398 
00399 } // End of namespace vcsn.
00400 
00401 #endif // ! VCSN_ALGORITHMS_INFILTRATION_HXX