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

# 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 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 # include <vaucanson/algorithms/realtime.hh>
    00027
    00028 # include <vaucanson/automata/concept/automata_base.hh>
    00029 # include <vaucanson/misc/usual_macros.hh>
    00030 # include <vaucanson/automata/implementation/geometry.hh>
    00031 # include <vaucanson/misc/static.hh>
    00032
    00033 namespace vcsn
    00034 {
    00035
    00036   /*--------------------------------.
    00037   | Functor for product algorithm.  |
    00038   `--------------------------------*/
    00039   template<typename A, typename T, typename U>
    00040   class Product
    00041   {
    00042     public:
    00043       typedef AutomataBase<A> structure_t;
    00044       typedef Element<A, T> lhs_t;
    00045       typedef Element<A, U> rhs_t;
    00046       typedef lhs_t         output_t;
    00047       typedef std::map<hstate_t, std::pair<hstate_t, hstate_t> > pair_map_t;
    00048
    00049       Product (const structure_t& structure,
    00050                const bool use_geometry)
    00051         : use_geometry_(use_geometry),
    00052           series_(structure.series()),
    00053           monoid_(series_.monoid()),
    00054           semiring_zero_(series_.semiring().zero(SELECT(semiring_elt_value_t)))
    00055       {
    00056       }
    00057
    00058       // returns the product of @c lhs and @c rhs (and put it also in @c output)
    00059       output_t&
    00060       operator() (output_t& output,
    00061                   const lhs_t& lhs,
    00062                   const rhs_t& rhs,
    00063                   pair_map_t& m)
    00064       {
    00065         TIMER_SCOPED("product");
    00066         visited_.clear();
    00067
    00068         precondition(is_realtime(lhs));
    00069         precondition(is_realtime(rhs));
    00070
    00071         this->initialize_queue(output, lhs, rhs, m);
    00072
    00073         delta_ret_t transition_lhs;
    00074         delta_ret_t transition_rhs;
    00075         while (not to_process_.empty())
    00076         {
    00077           const pair_hstate_t current_pair = to_process_.front();
    00078           to_process_.pop();
    00079
    00080           const hstate_t lhs_s       = current_pair.first;
    00081           const hstate_t rhs_s       = current_pair.second;
    00082           const hstate_t current_state = visited_[current_pair];
    00083
    00084           output.set_initial(current_state,
    00085                              lhs.get_initial(lhs_s) * rhs.get_initial(rhs_s));
    00086           output.set_final(current_state,
    00087                            lhs.get_final(lhs_s) * rhs.get_final(rhs_s));
    00088
    00089           transition_lhs.clear();
    00090           transition_rhs.clear();
    00091           lhs.deltac(transition_lhs, lhs_s, delta_kind::transitions());
    00092           rhs.deltac(transition_rhs, rhs_s, delta_kind::transitions());
    00093
    00094           for_all_const_(delta_ret_t, l, transition_lhs)
    00095             for_all_const_(delta_ret_t, r, transition_rhs)
    00096             {
    00097               series_set_elt_t  prod_series(series_);
    00098
    00099               if (is_product_not_null(lhs, rhs, l, r, prod_series))
    00100               {
    00101                 const pair_hstate_t new_pair(lhs.dst_of(*l), rhs.dst_of(*r));
    00102                 typename visited_t::const_iterator found = visited_.find(new_pair);
    00103
    00104                 hstate_t dst;
    00105                 if (found == visited_.end())
    00106                 {
    00107                   dst = output.add_state();
    00108
    00109                   this->add_state_to_process(output, lhs, rhs, m, dst, new_pair);
    00110                 }
    00111                 else
    00112                   dst = found->second;
    00113                 output.add_series_transition(current_state, dst, prod_series);
    00114               }
    00115             }
    00116         }
    00117         return output;
    00118       }
    00119
    00120     private:
    00121       // Some little graphic tools
    00122       class grphx
    00123       {
    00124         public:
    00125           template <typename Output, typename Lhs, typename Rhs>
    00126           static void
    00127           setcoordfrom (Output& a,
    00128                         const Lhs& lhs,
    00129                         const Rhs& rhs,
    00130                         const hstate_t state,
    00131                         const hstate_t x_state,
    00132                         const hstate_t y_state)
    00133           {
    00134             std::map<hstate_t, std::pair<double, double> >::const_iterator iter;
    00135             double x = 0, y = 0;
    00136
    00137             iter = lhs.geometry().states().find(x_state);
    00138             if (iter != lhs.geometry().states().end())
    00139               x = iter->second.first;
    00140
    00141             iter = rhs.geometry().states().find(y_state);
    00142             if (iter != rhs.geometry().states().end())
    00143               y = iter->second.second;
    00144
    00145             a.geometry().states()[state] = std::make_pair(x, y);
    00146           }
    00147         private:
    00148           // Diagonal alignement with a depth-first traversal
    00149           template<typename I>
    00150           void
    00151           align (const I& a)
    00152           {
    00153             AUTOMATON_TYPES(I);
    00154             std::map<hstate_t,bool> visited;
    00155             std::stack<hstate_t> stack;
    00156
    00157             for_all_states(i, a)
    00158               {
    00159                 visited[*i] = false;
    00160                 // ensure inaccessible states will be visited
    00161                 stack.push(*i);
    00162               }
    00163
    00164             for_all_initial_states(i, a)
    00165               stack.push(*i);
    00166
    00167             int x = 0;
    00168             while (!stack.empty())
    00169             {
    00170               hstate_t i = stack.top();
    00171               stack.pop();
    00172
    00173               if (!visited[i])
    00174               {
    00175                 visited[i] = true;
    00176
    00177                 a.geometry()[i] = std::make_pair(x, x);
    00178                 x++;
    00179
    00180                 std::vector<htransition_t> dst;
    00181                 a.deltac(dst, i, delta_kind::transitions());
    00182                 for_all_const_(std::vector<htransition_t>, j, dst)
    00183                   stack.push(a.dst_of(*j));
    00184               }
    00185             }
    00186           }
    00187
    00188       };
    00189       class no_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 hstate_t state,
    00198                         const hstate_t x_state,
    00199                         const hstate_t y_state) {};
    00200       };
    00201
    00202       // useful typedefs
    00203       AUTOMATON_TYPES(output_t);
    00204
    00205       typedef std::pair<hstate_t, hstate_t>             pair_hstate_t;
    00206       typedef std::set<htransition_t>                   delta_ret_t;
    00207       typedef std::map<pair_hstate_t, hstate_t>         visited_t;
    00208       typedef typename series_set_elt_t::support_t      support_t;
    00209
    00210       // add a @c new_state in the queue
    00211       inline void
    00212       add_state_to_process (output_t& output,
    00213                             const lhs_t& lhs,
    00214                             const rhs_t& rhs,
    00215                             pair_map_t& m,
    00216                             const hstate_t& new_state,
    00217                             const pair_hstate_t& new_pair)
    00218       {
    00219         m[new_state] = new_pair;
    00220         visited_[new_pair] = new_state;
    00221         to_process_.push(new_pair);
    00222
    00223 # define if_(Cond, ThenClause, ElseClause)                      \
    00224   misc::static_if_simple<Cond, ThenClause, ElseClause>::t
    00225 # define eq_(Type1, Type2)                      \
    00226   misc::static_eq<Type1, Type2>::value
    00227
    00228         if (use_geometry_)
    00229           if_(eq_(typename output_t::geometry_t, geometry) and  \
    00230               eq_(typename rhs_t::geometry_t, geometry) and             \
    00231               eq_(typename lhs_t::geometry_t, geometry),                \
    00232               grphx, no_grphx)
    00233             ::setcoordfrom(output, lhs, rhs,
    00234                            new_state, new_pair.first, new_pair.second);
    00235 # undef if_
    00236 # undef eq_
    00237       }
    00238
    00239       // initialize queue with all pairs of intials states from @c lhs and @c rhs
    00240       inline void
    00241       initialize_queue (output_t& output,
    00242                         const lhs_t& lhs,
    00243                         const rhs_t& rhs,
    00244                         pair_map_t& m)
    00245       {
    00246         for_all_initial_states(lhs_s, lhs)
    00247           for_all_initial_states(rhs_s, rhs)
    00248           {
    00249             const pair_hstate_t new_pair(*lhs_s, *rhs_s);
    00250             const hstate_t      new_state = output.add_state();
    00251
    00252             this->add_state_to_process(output, lhs, rhs, m, new_state, new_pair);
    00253           }
    00254       }
    00255
    00256       inline bool
    00257       is_product_not_null (const lhs_t& lhs,
    00258                            const rhs_t& rhs,
    00259                            const delta_ret_t::const_iterator& l,
    00260                            const delta_ret_t::const_iterator& r,
    00261                            series_set_elt_t&  prod_series) const
    00262       {
    00263         const series_set_elt_t  left_series  = lhs.series_of(*l);
    00264         const series_set_elt_t  right_series = rhs.series_of(*r);
    00265
    00266         bool                    prod_is_not_null = false;
    00267         for_all_(support_t, supp, left_series.supp())
    00268           {
    00269             const monoid_elt_t   supp_elt (monoid_, *supp);
    00270             const semiring_elt_t l = left_series.get(supp_elt);
    00271             const semiring_elt_t r = right_series.get(supp_elt);
    00272             const semiring_elt_t p = l * r;
    00273             if (p != semiring_zero_)
    00274             {
    00275               prod_series.assoc(*supp, p.value());
    00276               prod_is_not_null = true;
    00277             }
    00278           }
    00279         return (prod_is_not_null);
    00280       }
    00281
    00282       // If set to true, <geometry> tags of the result automaton should be filled
    00283       const bool        use_geometry_;
    00284
    00285       // keep traces of new states created
    00286       visited_t                 visited_;
    00287       // @c to_process_ stores all states of output that needs are not
    00288       std::queue<pair_hstate_t> to_process_;
    00289
    00290       // frequently used objects in computation
    00291       const series_set_t&       series_;
    00292       const monoid_t&           monoid_;
    00293       // This variable's type must not be set to a reference.
    00294       const semiring_elt_t      semiring_zero_;
    00295   };
    00296
    00297   /*-----------.
    00298   | Wrappers.  |
    00299   `-----------*/
    00300
    00301   template<typename A, typename T, typename U>
    00302   Element<A, T>
    00303   product (const Element<A, T>& lhs, const Element<A, U>& rhs,
    00304            std::map<hstate_t, std::pair<hstate_t, hstate_t> >& m,
    00305            const bool use_geometry)
    00306   {
    00307     Element<A, T> ret(rhs.structure());
    00308     Product<A, T, U> do_product(ret.structure(), use_geometry);
    00309     return do_product (ret, lhs, rhs, m);
    00310   }
    00311
    00312   template<typename A, typename T, typename U>
    00313   Element<A, T>
    00314   product (const Element<A, T>& lhs, const Element<A, U>& rhs,
    00315            const bool use_geometry)
    00316   {
    00317     std::map<hstate_t, std::pair<hstate_t, hstate_t> > m;
    00318     return product (lhs, rhs, m, use_geometry);
    00319   }
    00320
    00321 } // End of namespace vcsn.
    00322
    00323 #endif // ! VCSN_ALGORITHMS_PRODUCT_HXX