Vaucanson  1.4.1
rw_composition.hxx
1 // rw_composition.hxx: this file is part of the Vaucanson project.
2 //
3 // Vaucanson, a generic library for finite state machines.
4 //
5 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The
6 // Vaucanson Group.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 //
13 // The complete GNU General Public Licence Notice can be found as the
14 // `COPYING' file in the root directory.
15 //
16 // The Vaucanson Group consists of people listed in the `AUTHORS' file.
17 //
18 #ifndef VCSN_ALGORITHMS_RW_COMPOSITION_HXX
19 # define VCSN_ALGORITHMS_RW_COMPOSITION_HXX
20 
21 # include <map>
22 # include <queue>
23 # include <set>
24 
27 # include <vaucanson/automata/concept/transducer.hh>
28 // FIXME: The code for geometry computation must be enabled statically.
29 // (see product.hxx for some hints)
30 # include <vaucanson/automata/implementation/geometry.hh>
32 
33 namespace vcsn
34 {
35  template <typename U, typename Trans_t>
36  void
37  do_rw_composition(const TransducerBase<U>&,
38  const Trans_t& R,
39  const Trans_t& S,
40  Trans_t& T)
41  {
42  BENCH_TASK_SCOPED("rw_composition");
43 
44  // The second transducer must be realtime.
45  precondition(is_realtime(S));
46 
47  // Type helpers.
48  AUTOMATON_TYPES(Trans_t);
49  typedef series_set_elt_t exp_t;
50  typedef typename series_set_elt_t::semiring_elt_t output_exp_t;
51  typedef std::set<std::pair<hstate_t, output_exp_t> > state_exp_pair_set_t;
52  typedef typename std::map<hstate_t, typename Trans_t::geometry_t::coords_t>::const_iterator geom_iter_t;
53  typedef std::pair<hstate_t, hstate_t> state_pair_t;
54  typedef std::queue<state_pair_t> state_pair_queue_t;
55  typedef std::map<state_pair_t, hstate_t> state_pair_map_t;
56  typedef std::set<htransition_t> set_of_transitions_t;
57 
58  // Declare the main queue (FIFO).
59  state_pair_queue_t queue;
60 
61  // We will reuse this structure many times:
62  // each time we call partial_evaluation.
63  // Do not forget to clear() it before the call.
64  state_exp_pair_set_t sep_set;
65 
66  // Each time we create a new state in the output transducer
67  // (say a pair (p, r)), we will add it to the following map
68  // with the corresponding hstate_t, to speedup lookups.
69  state_pair_map_t Tstates;
70 
71  // These variables help us to create the new state geometry.
72  double xgeom;
73  double ygeom;
74  geom_iter_t iter;
75 
76  //
77  // Part 1 (refer to the algorithm description - see header).
78  // Initial states creation.
79  //
80 
81  monoid_elt_t Ridentity = R.series().monoid().identity(SELECT(monoid_elt_value_t));
82  monoid_elt_t Sidentity = S.series().monoid().identity(SELECT(monoid_elt_value_t));
83  monoid_elt_t Tidentity = T.series().monoid().identity(SELECT(monoid_elt_value_t));
84 
85  for_all_const_initial_states (p, R)
86  {
87  // Hold the initial weight of the state p in R.
88  // Warning: we suppose that the series on p is of the form: {w} 1, thus we
89  // can access the weight directly. But R is not required to be realtime,
90  // and there may be the series ({w} a) + ({z} b) on an initial state.
91  output_exp_t E = R.get_initial(*p).get(Ridentity);
92 
93  for_all_const_initial_states (q, S)
94  {
95  // Hold the initial weight of the state q in S.
96  // S is realtime, so we can access the weight directly.
97  output_exp_t F = S.get_initial(*q).get(Sidentity);
98 
99  // Partial evaluation.
100  sep_set.clear();
101  partial_evaluation(E, S, *q, sep_set);
102 
103  // Iterates throughout the partial_evaluation output.
104  for_all_const_(state_exp_pair_set_t, ig, sep_set)
105  {
106  // Construct the state representation (p, r).
107  state_pair_t sp;
108  sp.first = *p;
109  sp.second = (*ig).first;
110 
111  if (Tstates.find(sp) == Tstates.end())
112  {
113  // (p, r) does not exists yet in the output transducer.
114 
115  // So we create it,
116  hstate_t new_state = T.add_state();
117 
118  // add it the deduced geometry from p and r,
119  iter = R.geometry().states().find(*p);
120  if (iter != R.geometry().states().end())
121  xgeom = (*iter).second.first;
122  else
123  xgeom = 0;
124  iter = S.geometry().states().find(*q);
125  if (iter != S.geometry().states().end())
126  ygeom = (*iter).second.second;
127  else
128  ygeom = 0;
129  T.geometry().states()[new_state] = std::make_pair(xgeom, ygeom);
130 
131  // store it in our lookup table,
132  Tstates[sp] = new_state;
133 
134  // Set the initial weight. (see hypothesis on R)
135  series_set_elt_t new_series(T.series());
136  new_series.assoc(Tidentity, F * ((*ig).second));
137  T.set_initial(new_state, new_series);
138 
139  // and finally push it in the queue.
140  queue.push(sp);
141  }
142  else
143  {
144  // (p, r) has already been created: we only update its initial
145  // weight.
146  series_set_elt_t new_series(T.series());
147  new_series.assoc(Tidentity, T.get_initial(Tstates[sp]).get(Tidentity) + F * ((*ig).second));
148  T.set_initial(Tstates[sp], new_series);
149  }
150  } // ! for_all_const_state_exp_pair_set_t
151  } // ! for_all_const_initial_states (S)
152  } // ! for_all_const_initial_states (R)
153 
154  //
155  // Part 2 (refer to the algorithm description - see header).
156  // Main loop (runs until the queue is exhausted).
157  //
158 
159  while (not queue.empty())
160  {
161  // Pop one state from the queue.
162  const state_pair_t sp = queue.front();
163  queue.pop();
164 
165  const hstate_t p = sp.first;
166  const hstate_t q = sp.second;
167 
168  // Build (p, x, E, s).
169  for (delta_iterator e(R.value(), p); !e.done(); e.next())
170  {
171  hstate_t s = R.dst_of(*e);
172  exp_t E = R.series_of(*e);
173 
174  // R is not required to be realtime so we must iterate over the support
175  // of E.
176  for_all_const_(series_set_elt_t::support_t, y, E.supp())
177  {
178  const monoid_elt_t x(E.structure().monoid(), *y);
179 
180  // Partial evaluation.
181  sep_set.clear();
182  partial_evaluation(E.get(x), S, q, sep_set);
183 
184  for_all_const_(state_exp_pair_set_t, ig, sep_set)
185  {
186  // Construct the state representation (s, r).
187  state_pair_t sp1;
188  sp1.first = s;
189  sp1.second = (*ig).first;
190 
191  if (Tstates.find(sp1) == Tstates.end())
192  {
193  // (s, r) does not exists yet in the output transducer.
194 
195  // So we create it,
196  hstate_t new_state = T.add_state();
197 
198  // add it the deduced geometry from s and r,
199  iter = R.geometry().states().find(sp1.first);
200  if (iter != R.geometry().states().end())
201  xgeom = (*iter).second.first;
202  else
203  xgeom = 0;
204  iter = S.geometry().states().find(sp1.second);
205  if (iter != S.geometry().states().end())
206  ygeom = (*iter).second.second;
207  else
208  ygeom = 0;
209  T.geometry().states()[new_state] = std::make_pair(xgeom, ygeom);
210 
211  // store it in our lookup table,
212  Tstates[sp1] = new_state;
213 
214  // and finally push it in the queue.
215  queue.push(sp1);
216  }
217 
218  exp_t Gexp(R.structure().series());
219  Gexp.assoc(x, (*ig).second);
220  T.add_series_transition(Tstates[sp], Tstates[sp1], Gexp);
221  } // ! for_all_const_state_exp_pair_set_t
222  } // ! for_all_const_series_set_elt_t::support_t
223  } // ! outgoing transitions from p in R
224 
225  // Handle final states.
226  if (R.is_final(p))
227  {
228  // Partial evaluation.
229  // The same hypothesis on the final states than for initial states hold.
230  sep_set.clear();
231  partial_evaluation(R.get_final(p).get(Ridentity), S, q, sep_set);
232 
233  for_all_const_(state_exp_pair_set_t, ig, sep_set)
234  {
235  const hstate_t r = (*ig).first;
236  if (S.is_final(r))
237  {
238  series_set_elt_t new_series(T.series());
239  // S is realtime so we can directly access the final weight.
240  new_series.assoc(Tidentity, (*ig).second * S.get_final(r).get(Sidentity));
241  T.set_final(Tstates[sp], new_series);
242  }
243  }
244  } // ! is_final
245  } // ! main loop
246  }
247 
248  // Wrapper around do_rw_composition.
249  template <typename S, typename T>
250  void
252  const Element<S, T>& rhs,
253  Element<S, T>& ret)
254  {
255  // Type helpers.
256  typedef Element<S, T> auto_t;
257  AUTOMATON_TYPES(auto_t);
258 
259  // We need to make sure RET is empty before passing it
260  // to do_rw_composition(), therefore it won't work if
261  // RET refers to the same automaton as LHS or RHS.
262  precondition(&ret != &lhs);
263  precondition(&ret != &rhs);
264 
265  // Remove all the state from ret.
266  for_all_states (s, ret)
267  ret.del_state(*s);
268 
269  do_rw_composition(lhs.structure(), lhs, rhs, ret);
270  }
271 
272  // This wrapper creates a new automaton. No
273  // special care needs be taken.
274  template <typename S, typename T>
275  Element<S, T>
277  {
278  // Create an empty automaton based on the lhs structure.
279  Element<S, T> ret(lhs.structure());
280 
281  do_rw_composition(lhs.structure(), lhs, rhs, ret);
282  return ret;
283  }
284 
285 } // ! vcsn
286 
287 #endif // ! VCSN_ALGORITHMS_RW_COMPOSITION_HXX