Vaucanson 1.4
|
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