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

Generated on Thu Oct 9 20:22:41 2008 for Vaucanson by  doxygen 1.5.1