Vaucanson 1.4
rw_composition.hxx
00001 // rw_composition.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, 2009 The
00006 // Vaucanson Group.
00007 //
00008 // This program is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU General Public License
00010 // as published by the Free Software Foundation; either version 2
00011 // of the License, or (at your option) any later version.
00012 //
00013 // The complete GNU General Public Licence Notice can be found as the
00014 // `COPYING' file in the root directory.
00015 //
00016 // The Vaucanson Group consists of people listed in the `AUTHORS' file.
00017 //
00018 #ifndef VCSN_ALGORITHMS_RW_COMPOSITION_HXX
00019 # define VCSN_ALGORITHMS_RW_COMPOSITION_HXX
00020 
00021 # include <map>
00022 # include <queue>
00023 # include <set>
00024 
00025 # include <vaucanson/algorithms/rw_composition.hh>
00026 # include <vaucanson/algorithms/realtime.hh>
00027 # include <vaucanson/automata/concept/transducer.hh>
00028 // FIXME: The code for geometry computation must be enabled statically.
00029 // (see product.hxx for some hints)
00030 # include <vaucanson/automata/implementation/geometry.hh>
00031 # include <vaucanson/algorithms/internal/evaluation.hh>
00032 
00033 namespace vcsn
00034 {
00035   template <typename U, typename Trans_t>
00036   void
00037   do_rw_composition(const TransducerBase<U>&,
00038                     const Trans_t& R,
00039                     const Trans_t& S,
00040                     Trans_t& T)
00041   {
00042     BENCH_TASK_SCOPED("rw_composition");
00043 
00044     // The second transducer must be realtime.
00045     precondition(is_realtime(S));
00046 
00047     // Type helpers.
00048     AUTOMATON_TYPES(Trans_t);
00049     typedef series_set_elt_t exp_t;
00050     typedef typename series_set_elt_t::semiring_elt_t output_exp_t;
00051     typedef std::set<std::pair<hstate_t, output_exp_t> > state_exp_pair_set_t;
00052     typedef typename std::map<hstate_t, typename Trans_t::geometry_t::coords_t>::const_iterator geom_iter_t;
00053     typedef std::pair<hstate_t, hstate_t> state_pair_t;
00054     typedef std::queue<state_pair_t> state_pair_queue_t;
00055     typedef std::map<state_pair_t, hstate_t> state_pair_map_t;
00056     typedef std::set<htransition_t> set_of_transitions_t;
00057 
00058     // Declare the main queue (FIFO).
00059     state_pair_queue_t queue;
00060 
00061     // We will reuse this structure many times:
00062     // each time we call partial_evaluation.
00063     // Do not forget to clear() it before the call.
00064     state_exp_pair_set_t sep_set;
00065 
00066     // Each time we create a new state in the output transducer
00067     // (say a pair (p, r)), we will add it to the following map
00068     // with the corresponding hstate_t, to speedup lookups.
00069     state_pair_map_t Tstates;
00070 
00071     // These variables help us to create the new state geometry.
00072     double xgeom;
00073     double ygeom;
00074     geom_iter_t iter;
00075 
00076     //
00077     // Part 1 (refer to the algorithm description - see header).
00078     // Initial states creation.
00079     //
00080 
00081     monoid_elt_t Ridentity = R.series().monoid().identity(SELECT(monoid_elt_value_t));
00082     monoid_elt_t Sidentity = S.series().monoid().identity(SELECT(monoid_elt_value_t));
00083     monoid_elt_t Tidentity = T.series().monoid().identity(SELECT(monoid_elt_value_t));
00084 
00085     for_all_const_initial_states (p, R)
00086     {
00087       // Hold the initial weight of the state p in R.
00088       // Warning: we suppose that the series on p is of the form: {w} 1, thus we
00089       // can access the weight directly. But R is not required to be realtime,
00090       // and there may be the series ({w} a) + ({z} b) on an initial state.
00091       output_exp_t E = R.get_initial(*p).get(Ridentity);
00092 
00093       for_all_const_initial_states (q, S)
00094       {
00095         // Hold the initial weight of the state q in S.
00096         // S is realtime, so we can access the weight directly.
00097         output_exp_t F = S.get_initial(*q).get(Sidentity);
00098 
00099         // Partial evaluation.
00100         sep_set.clear();
00101         partial_evaluation(E, S, *q, sep_set);
00102 
00103         // Iterates throughout the partial_evaluation output.
00104         for_all_const_(state_exp_pair_set_t, ig, sep_set)
00105         {
00106           // Construct the state representation (p, r).
00107           state_pair_t sp;
00108           sp.first = *p;
00109           sp.second = (*ig).first;
00110 
00111           if (Tstates.find(sp) == Tstates.end())
00112           {
00113             // (p, r) does not exists yet in the output transducer.
00114 
00115             // So we create it,
00116             hstate_t new_state = T.add_state();
00117 
00118             // add it the deduced geometry from p and r,
00119             iter = R.geometry().states().find(*p);
00120             if (iter != R.geometry().states().end())
00121               xgeom = (*iter).second.first;
00122             else
00123               xgeom = 0;
00124             iter = S.geometry().states().find(*q);
00125             if (iter != S.geometry().states().end())
00126               ygeom = (*iter).second.second;
00127             else
00128               ygeom = 0;
00129             T.geometry().states()[new_state] = std::make_pair(xgeom, ygeom);
00130 
00131             // store it in our lookup table,
00132             Tstates[sp] = new_state;
00133 
00134             // Set the initial weight. (see hypothesis on R)
00135             series_set_elt_t new_series(T.series());
00136             new_series.assoc(Tidentity, F * ((*ig).second));
00137             T.set_initial(new_state, new_series);
00138 
00139             // and finally push it in the queue.
00140             queue.push(sp);
00141           }
00142           else
00143           {
00144             // (p, r) has already been created: we only update its initial
00145             // weight.
00146             series_set_elt_t new_series(T.series());
00147             new_series.assoc(Tidentity, T.get_initial(Tstates[sp]).get(Tidentity) + F * ((*ig).second));
00148             T.set_initial(Tstates[sp], new_series);
00149           }
00150         } // ! for_all_const_state_exp_pair_set_t
00151       } // ! for_all_const_initial_states (S)
00152     } // ! for_all_const_initial_states (R)
00153 
00154     //
00155     // Part 2 (refer to the algorithm description - see header).
00156     // Main loop (runs until the queue is exhausted).
00157     //
00158 
00159     while (not queue.empty())
00160     {
00161       // Pop one state from the queue.
00162       const state_pair_t sp = queue.front();
00163       queue.pop();
00164 
00165       const hstate_t p = sp.first;
00166       const hstate_t q = sp.second;
00167 
00168       // Build (p, x, E, s).
00169       for (delta_iterator e(R.value(), p); !e.done(); e.next())
00170       {
00171         hstate_t s = R.dst_of(*e);
00172         exp_t E = R.series_of(*e);
00173 
00174         // R is not required to be realtime so we must iterate over the support
00175         // of E.
00176         for_all_const_(series_set_elt_t::support_t, y, E.supp())
00177         {
00178           const monoid_elt_t x(E.structure().monoid(), *y);
00179 
00180           // Partial evaluation.
00181           sep_set.clear();
00182           partial_evaluation(E.get(x), S, q, sep_set);
00183 
00184           for_all_const_(state_exp_pair_set_t, ig, sep_set)
00185           {
00186             // Construct the state representation (s, r).
00187             state_pair_t sp1;
00188             sp1.first = s;
00189             sp1.second = (*ig).first;
00190 
00191             if (Tstates.find(sp1) == Tstates.end())
00192             {
00193               // (s, r) does not exists yet in the output transducer.
00194 
00195               // So we create it,
00196               hstate_t new_state = T.add_state();
00197 
00198               // add it the deduced geometry from s and r,
00199               iter = R.geometry().states().find(sp1.first);
00200               if (iter != R.geometry().states().end())
00201                 xgeom = (*iter).second.first;
00202               else
00203                 xgeom = 0;
00204               iter = S.geometry().states().find(sp1.second);
00205               if (iter != S.geometry().states().end())
00206                 ygeom = (*iter).second.second;
00207               else
00208                 ygeom = 0;
00209               T.geometry().states()[new_state] = std::make_pair(xgeom, ygeom);
00210 
00211               // store it in our lookup table,
00212               Tstates[sp1] = new_state;
00213 
00214               // and finally push it in the queue.
00215               queue.push(sp1);
00216             }
00217 
00218             exp_t Gexp(R.structure().series());
00219             Gexp.assoc(x, (*ig).second);
00220             T.add_series_transition(Tstates[sp], Tstates[sp1], Gexp);
00221           } // ! for_all_const_state_exp_pair_set_t
00222         } // ! for_all_const_series_set_elt_t::support_t
00223       } // ! outgoing transitions from p in R
00224 
00225       // Handle final states.
00226       if (R.is_final(p))
00227       {
00228         // Partial evaluation.
00229         // The same hypothesis on the final states than for initial states hold.
00230         sep_set.clear();
00231         partial_evaluation(R.get_final(p).get(Ridentity), S, q, sep_set);
00232 
00233         for_all_const_(state_exp_pair_set_t, ig, sep_set)
00234         {
00235           const hstate_t r = (*ig).first;
00236           if (S.is_final(r))
00237           {
00238             series_set_elt_t new_series(T.series());
00239             // S is realtime so we can directly access the final weight.
00240             new_series.assoc(Tidentity, (*ig).second * S.get_final(r).get(Sidentity));
00241             T.set_final(Tstates[sp], new_series);
00242           }
00243         }
00244       } // ! is_final
00245     } // ! main loop
00246   }
00247 
00248   // Wrapper around do_rw_composition.
00249   template <typename S, typename T>
00250   void
00251   rw_composition(const Element<S, T>& lhs,
00252                  const Element<S, T>& rhs,
00253                  Element<S, T>& ret)
00254   {
00255     // Type helpers.
00256     typedef Element<S, T> auto_t;
00257     AUTOMATON_TYPES(auto_t);
00258 
00259     // We need to make sure RET is empty before passing it
00260     // to do_rw_composition(), therefore it won't work if
00261     // RET refers to the same automaton as LHS or RHS.
00262     precondition(&ret != &lhs);
00263     precondition(&ret != &rhs);
00264 
00265     // Remove all the state from ret.
00266     for_all_states (s, ret)
00267       ret.del_state(*s);
00268 
00269     do_rw_composition(lhs.structure(), lhs, rhs, ret);
00270   }
00271 
00272   // This wrapper creates a new automaton. No
00273   // special care needs be taken.
00274   template <typename S, typename T>
00275   Element<S, T>
00276   rw_composition(const Element<S, T>& lhs, const Element<S, T>& rhs)
00277   {
00278     // Create an empty automaton based on the lhs structure.
00279     Element<S, T> ret(lhs.structure());
00280 
00281     do_rw_composition(lhs.structure(), lhs, rhs, ret);
00282     return ret;
00283   }
00284 
00285 } // ! vcsn
00286 
00287 #endif // ! VCSN_ALGORITHMS_RW_COMPOSITION_HXX