Vaucanson 1.4
product.hxx
00001 // product.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_PRODUCT_HXX
00018 # define VCSN_ALGORITHMS_PRODUCT_HXX
00019 
00020 # include <set>
00021 # include <map>
00022 # include <queue>
00023 # include <stack>
00024 
00025 # include <vaucanson/algorithms/product.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 product algorithm.  |
00041 `--------------------------------*/
00042 template<typename A, typename T, typename U>
00043 class Product
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     Product (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 product 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("product");
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             series_set_elt_t    prod_series(series_);
00088             if (is_product_not_null(lhs.get_initial(lhs_s), rhs.get_initial(rhs_s), prod_series))
00089                         output.set_initial(current_state, prod_series);
00090   }
00091   {
00092             series_set_elt_t    prod_series(series_);
00093             if (is_product_not_null(lhs.get_final(lhs_s), rhs.get_final(rhs_s), prod_series))
00094                         output.set_final(current_state, prod_series);
00095   }
00096         for (typename lhs_t::delta_iterator l(lhs.value(), lhs_s);
00097              ! l.done();
00098              l.next())
00099           for (typename rhs_t::delta_iterator r(rhs.value(), rhs_s);
00100                ! r.done();
00101                r.next())
00102           {
00103             series_set_elt_t    prod_series(series_);
00104 
00105             if (is_product_not_null(lhs.series_of(*l), rhs.series_of(*r), prod_series))
00106             {
00107               const pair_hstate_t new_pair(lhs.dst_of(*l), rhs.dst_of(*r));
00108               typename visited_t::const_iterator found = visited_.find(new_pair);
00109 
00110               hstate_t dst;
00111               if (found == visited_.end())
00112               {
00113                 dst = output.add_state();
00114 
00115                 this->add_state_to_process(output, lhs, rhs, m, dst, new_pair);
00116               }
00117               else
00118                 dst = found->second;
00119               output.add_series_transition(current_state, dst, prod_series);
00120             }
00121           }
00122       }
00123       return output;
00124     }
00125 
00126   private:
00127     // Some little graphic tools
00128     class grphx
00129     {
00130       public:
00131         template <typename Output, typename Lhs, typename Rhs>
00132         static void
00133         setcoordfrom (Output& a,
00134                       const Lhs& lhs,
00135                       const Rhs& rhs,
00136                       const typename Output::hstate_t state,
00137                       const typename Lhs::hstate_t x_state,
00138                       const typename Rhs::hstate_t y_state)
00139         {
00140           typename std::map<typename Lhs::hstate_t,
00141             typename Lhs::geometry_t::coords_t>::const_iterator iter;
00142           typename std::map<typename Rhs::hstate_t,
00143             typename Rhs::geometry_t::coords_t>::const_iterator iter2;
00144           double x = 0, y = 0;
00145 
00146           iter = lhs.geometry().states().find(x_state);
00147           if (iter != lhs.geometry().states().end())
00148             x = iter->second.first;
00149 
00150           iter2 = rhs.geometry().states().find(y_state);
00151           if (iter2 != rhs.geometry().states().end())
00152             y = iter2->second.second;
00153 
00154           a.geometry().states()[state] = std::make_pair(x, y);
00155         }
00156       private:
00157         // Diagonal alignement with a depth-first traversal
00158         template<typename I>
00159         void
00160         align (const I& a)
00161         {
00162           AUTOMATON_TYPES(I);
00163           std::map<hstate_t,bool> visited;
00164           std::stack<hstate_t> stack;
00165 
00166           for_all_const_states(i, a)
00167             {
00168               visited[*i] = false;
00169               // ensure inaccessible states will be visited
00170               stack.push(*i);
00171             }
00172 
00173           for_all_const_initial_states(i, a)
00174             stack.push(*i);
00175 
00176           int x = 0;
00177           while (!stack.empty())
00178           {
00179             hstate_t i = stack.top();
00180             stack.pop();
00181 
00182             if (!visited[i])
00183             {
00184               visited[i] = true;
00185 
00186               a.geometry()[i] = std::make_pair(x, x);
00187               x++;
00188 
00189               for (delta_iterator j(a.value(), i);
00190                    ! j.done();
00191                    j.next())
00192                 stack.push(a.dst_of(*j));
00193             }
00194           }
00195         }
00196 
00197     };
00198     class no_grphx
00199     {
00200       public:
00201         template <typename Output, typename Lhs, typename Rhs>
00202         static void
00203         setcoordfrom (Output& a,
00204                       const Lhs& lhs,
00205                       const Rhs& rhs,
00206                       const typename Output::hstate_t state,
00207                       const typename Lhs::hstate_t x_state,
00208                       const typename Rhs::hstate_t y_state) {};
00209     };
00210 
00211     // useful typedefs
00212     AUTOMATON_TYPES(output_t);
00213 
00214     typedef std::pair<typename lhs_t::hstate_t, typename rhs_t::hstate_t>
00215                                                       pair_hstate_t;
00216     typedef std::list<htransition_t>                    delta_ret_t;
00217     typedef std::map<pair_hstate_t, hstate_t>           visited_t;
00218     typedef typename series_set_elt_t::support_t        support_t;
00219 
00220     // add a @c new_state in the queue
00221     inline void
00222     add_state_to_process (output_t& output,
00223                           const lhs_t& lhs,
00224                           const rhs_t& rhs,
00225                           pair_map_t& m,
00226                           const hstate_t& new_state,
00227                           const pair_hstate_t& new_pair)
00228     {
00229       m[new_state] = new_pair;
00230       visited_[new_pair] = new_state;
00231       to_process_.push(new_pair);
00232 
00233 # define if_(Cond, ThenClause, ElseClause)                      \
00234 misc::static_if_simple<Cond, ThenClause, ElseClause>::t
00235 # define eq_(Type1, Type2)                      \
00236 misc::static_eq<Type1, Type2>::value
00237 # define DECLARE_GEOMETRY(Type) \
00238   typedef geometry<typename Type::hstate_t, typename Type::htransition_t, typename Type::geometry_coords_t> geometry_ ## Type ;
00239 
00240       DECLARE_GEOMETRY(output_t)
00241       DECLARE_GEOMETRY(lhs_t)
00242       DECLARE_GEOMETRY(rhs_t)
00243       if (use_geometry_)
00244         if_(eq_(typename output_t::geometry_t, geometry_output_t)  and \
00245             eq_(typename rhs_t::geometry_t, geometry_rhs_t) and \
00246             eq_(typename lhs_t::geometry_t, geometry_lhs_t),    \
00247             grphx, no_grphx)
00248           ::setcoordfrom(output, lhs, rhs,
00249                          new_state, new_pair.first, new_pair.second);
00250 # undef if_
00251 # undef eq_
00252     }
00253 
00254     // initialize queue with all pairs of intials states from @c lhs and @c rhs
00255     inline void
00256     initialize_queue (output_t& output,
00257                       const lhs_t& lhs,
00258                       const rhs_t& rhs,
00259                       pair_map_t& m)
00260     {
00261       for_all_const_initial_states(lhs_s, lhs)
00262         for_all_const_initial_states(rhs_s, rhs)
00263         {
00264           const pair_hstate_t   new_pair(*lhs_s, *rhs_s);
00265           const hstate_t        new_state = output.add_state();
00266 
00267           this->add_state_to_process(output, lhs, rhs, m, new_state, new_pair);
00268         }
00269     }
00270 
00271     inline bool
00272     is_product_not_null (const series_set_elt_t left_series,
00273                          const series_set_elt_t right_series,
00274                          series_set_elt_t&  prod_series) const
00275     {
00276       bool                      prod_is_not_null = false;
00277       //the alphabet of rhs is a subset of the alphbet of rhs
00278       //thus, we consider monomials in right_series; they are compatible with lhs.
00279       for_all_(support_t, supp, right_series.supp())
00280         {
00281           const monoid_elt_t     supp_elt (monoid_, *supp);
00282           const semiring_elt_t l = left_series.get(supp_elt);
00283           const semiring_elt_t r = right_series.get(supp_elt);
00284           const semiring_elt_t p = l * r;
00285           if (p != semiring_zero_)
00286           {
00287             prod_series.assoc(*supp, p.value());
00288             prod_is_not_null = true;
00289           }
00290         }
00291       return (prod_is_not_null);
00292     }
00293 
00294     // If set to true, <geometry> tags of the result automaton should be filled
00295     const bool  use_geometry_;
00296 
00297     // keep traces of new states created
00298     visited_t                   visited_;
00299     // @c to_process_ stores all states of output that needs are not
00300     std::queue<pair_hstate_t>   to_process_;
00301 
00302     // frequently used objects in computation
00303     const series_set_t& series_;
00304     const monoid_t&             monoid_;
00305     // This variable's type must not be set to a reference.
00306     const semiring_elt_t        semiring_zero_;
00307 };
00308 
00309 /*-----------.
00310 | Wrappers.  |
00311 `-----------*/
00312 
00313 template<typename A, typename T, typename U>
00314 Element<A, T>
00315 product (const Element<A, T>& lhs, const Element<A, U>& rhs,
00316          std::map<typename T::hstate_t,
00317          std::pair<typename T::hstate_t, typename U::hstate_t> >& m,
00318          const bool use_geometry)
00319 {
00320   Element<A, T> ret(lhs.structure());
00321   Product<A, T, U> do_product(ret.structure(), use_geometry);
00322   return do_product (ret, lhs, rhs, m);
00323 }
00324 
00325 template<typename A, typename T, typename U>
00326 Element<A, T>
00327 product (const Element<A, T>& lhs, const Element<A, U>& rhs,
00328          const bool use_geometry)
00329 {
00330   std::map<typename T::hstate_t,
00331     std::pair<typename T::hstate_t, typename U::hstate_t> > m;
00332   return product (lhs, rhs, m, use_geometry);
00333 }
00334 
00335 } // End of namespace vcsn.
00336 
00337 #endif // ! VCSN_ALGORITHMS_PRODUCT_HXX