Vaucanson  1.4.1
shuffle.hxx
1 // shuffle.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, 2011 The Vaucanson Group.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // The complete GNU General Public Licence Notice can be found as the
13 // `COPYING' file in the root directory.
14 //
15 // The Vaucanson Group consists of people listed in the `AUTHORS' file.
16 //
17 #ifndef VCSN_ALGORITHMS_SHUFFLE_HXX
18 # define VCSN_ALGORITHMS_SHUFFLE_HXX
19 
20 # include <set>
21 # include <map>
22 # include <queue>
23 # include <stack>
24 
26 
27 # ifndef VCSN_NDEBUG
29 # endif // ! VCSN_NDEBUG
30 
31 # include <vaucanson/automata/concept/automata_base.hh>
32 # include <vaucanson/misc/usual_macros.hh>
33 # include <vaucanson/automata/implementation/geometry.hh>
34 # include <vaucanson/misc/static.hh>
35 
36 namespace vcsn
37 {
38 
39 /*--------------------------------.
40 | Functor for shuffle algorithm. |
41 `--------------------------------*/
42 template<typename A, typename T, typename U>
43 class Shuffle
44 {
45  public:
46  typedef AutomataBase<A> structure_t;
47  typedef Element<A, T> lhs_t;
48  typedef Element<A, U> rhs_t;
49  typedef lhs_t output_t;
50  typedef std::map<typename output_t::hstate_t,
51  std::pair<typename lhs_t::hstate_t, typename rhs_t::hstate_t> >
52  pair_map_t;
53 
54  Shuffle (const structure_t& structure,
55  const bool use_geometry)
56  : use_geometry_(use_geometry),
57  series_(structure.series()),
58  monoid_(series_.monoid()),
59  semiring_zero_(series_.semiring().zero(SELECT(semiring_elt_value_t)))
60  {
61  }
62 
63  // returns the shuffle of @c lhs and @c rhs (and put it also in @c output)
64  output_t&
65  operator() (output_t& output,
66  const lhs_t& lhs,
67  const rhs_t& rhs,
68  pair_map_t& m)
69  {
70  BENCH_TASK_SCOPED("shuffle");
71  visited_.clear();
72 
73  precondition(is_realtime(lhs));
74  precondition(is_realtime(rhs));
75 
76  this->initialize_queue(output, lhs, rhs, m);
77 
78  while (not to_process_.empty())
79  {
80  const pair_hstate_t current_pair = to_process_.front();
81  to_process_.pop();
82 
83  const hstate_t lhs_s = current_pair.first;
84  const hstate_t rhs_s = current_pair.second;
85  const hstate_t current_state = visited_[current_pair];
86 
87  output.set_initial(current_state,
88  lhs.get_initial(lhs_s) * rhs.get_initial(rhs_s));
89  output.set_final(current_state,
90  lhs.get_final(lhs_s) * rhs.get_final(rhs_s));
91 
92  for (typename lhs_t::delta_iterator l(lhs.value(), lhs_s);
93  ! l.done();
94  l.next())
95  {
96  const pair_hstate_t new_pair(lhs.dst_of(*l), rhs_s);
97  typename visited_t::const_iterator found = visited_.find(new_pair);
98 
99  hstate_t dst;
100  if (found == visited_.end())
101  {
102  dst = output.add_state();
103 
104  this->add_state_to_process(output, lhs, rhs, m, dst, new_pair);
105  }
106  else
107  dst = found->second;
108  output.add_series_transition(current_state, dst, lhs.series_of(*l));
109  }
110  for (typename rhs_t::delta_iterator r(rhs.value(), rhs_s);
111  ! r.done();
112  r.next())
113  {
114  const pair_hstate_t new_pair(lhs_s, rhs.dst_of(*r));
115  typename visited_t::const_iterator found = visited_.find(new_pair);
116 
117  hstate_t dst;
118  if (found == visited_.end())
119  {
120  dst = output.add_state();
121 
122  this->add_state_to_process(output, lhs, rhs, m, dst, new_pair);
123  }
124  else
125  dst = found->second;
126  output.add_series_transition(current_state, dst, rhs.series_of(*r));
127  }
128 
129 
130 
131  }
132  merge_transitions(output);
133  return output;
134  }
135 
136  private:
137  //merge transitions with the same ends
138  void merge_transitions(output_t& a)
139  {
140  typedef std::map<hstate_t, series_set_elt_t> map_t;
141  for_all_states(s, a)
142  {
143  map_t map;
144  std::list<htransition_t> transitions;
145  for (delta_iterator e(a.value(), *s); ! e.done(); e.next())
146  {
147  hstate_t target = a.dst_of(*e);
148  transitions.push_back(*e);
149  typename map_t::iterator it = map.find(target);
150  if (it == map.end())
151  map.insert(std::pair<hstate_t, series_set_elt_t>(target,
152  a.series_of(*e)));
153  else
154  it->second += a.series_of(*e);
155  }
156  for_all_(std::list<htransition_t>, e, transitions)
157  a.del_transition(*e);
158  for_all_(map_t, it, map)
159  if(it->second != a.series().zero_)
160  a.add_series_transition(*s, it->first, it->second);
161  }
162  }
163 
164  // Some little graphic tools
165  class grphx
166  {
167  public:
168  template <typename Output, typename Lhs, typename Rhs>
169  static void
170  setcoordfrom (Output& a,
171  const Lhs& lhs,
172  const Rhs& rhs,
173  const typename Output::hstate_t state,
174  const typename Lhs::hstate_t x_state,
175  const typename Rhs::hstate_t y_state)
176  {
177  typename std::map<typename Lhs::hstate_t,
178  typename Lhs::geometry_t::coords_t>::const_iterator iter;
179  typename std::map<typename Rhs::hstate_t,
180  typename Rhs::geometry_t::coords_t>::const_iterator iter2;
181  double x = 0, y = 0;
182 
183  iter = lhs.geometry().states().find(x_state);
184  if (iter != lhs.geometry().states().end())
185  x = iter->second.first;
186 
187  iter2 = rhs.geometry().states().find(y_state);
188  if (iter2 != rhs.geometry().states().end())
189  y = iter2->second.second;
190 
191  a.geometry().states()[state] = std::make_pair(x, y);
192  }
193  private:
194  // Diagonal alignement with a depth-first traversal
195  template<typename I>
196  void
197  align (const I& a)
198  {
199  AUTOMATON_TYPES(I);
200  std::map<hstate_t,bool> visited;
201  std::stack<hstate_t> stack;
202 
203  for_all_const_states(i, a)
204  {
205  visited[*i] = false;
206  // ensure inaccessible states will be visited
207  stack.push(*i);
208  }
209 
210  for_all_const_initial_states(i, a)
211  stack.push(*i);
212 
213  int x = 0;
214  while (!stack.empty())
215  {
216  hstate_t i = stack.top();
217  stack.pop();
218 
219  if (!visited[i])
220  {
221  visited[i] = true;
222 
223  a.geometry()[i] = std::make_pair(x, x);
224  x++;
225 
226  for (delta_iterator j(a.value(), i);
227  ! j.done();
228  j.next())
229  stack.push(a.dst_of(*j));
230  }
231  }
232  }
233 
234  };
235  class no_grphx
236  {
237  public:
238  template <typename Output, typename Lhs, typename Rhs>
239  static void
240  setcoordfrom (Output& a,
241  const Lhs& lhs,
242  const Rhs& rhs,
243  const typename Output::hstate_t state,
244  const typename Lhs::hstate_t x_state,
245  const typename Rhs::hstate_t y_state) {};
246  };
247 
248  // useful typedefs
249  AUTOMATON_TYPES(output_t);
250 
251  typedef std::pair<typename lhs_t::hstate_t, typename rhs_t::hstate_t>
252  pair_hstate_t;
253  typedef std::list<htransition_t> delta_ret_t;
254  typedef std::map<pair_hstate_t, hstate_t> visited_t;
255  typedef typename series_set_elt_t::support_t support_t;
256 
257  // add a @c new_state in the queue
258  inline void
259  add_state_to_process (output_t& output,
260  const lhs_t& lhs,
261  const rhs_t& rhs,
262  pair_map_t& m,
263  const hstate_t& new_state,
264  const pair_hstate_t& new_pair)
265  {
266  m[new_state] = new_pair;
267  visited_[new_pair] = new_state;
268  to_process_.push(new_pair);
269 
270 # define if_(Cond, ThenClause, ElseClause) \
271 misc::static_if_simple<Cond, ThenClause, ElseClause>::t
272 # define eq_(Type1, Type2) \
273 misc::static_eq<Type1, Type2>::value
274 # define DECLARE_GEOMETRY(Type) \
275  typedef geometry<typename Type::hstate_t, typename Type::htransition_t, typename Type::geometry_coords_t> geometry_ ## Type ;
276 
277  DECLARE_GEOMETRY(output_t)
278  DECLARE_GEOMETRY(lhs_t)
279  DECLARE_GEOMETRY(rhs_t)
280  if (use_geometry_)
281  if_(eq_(typename output_t::geometry_t, geometry_output_t) and \
282  eq_(typename rhs_t::geometry_t, geometry_rhs_t) and \
283  eq_(typename lhs_t::geometry_t, geometry_lhs_t), \
284  grphx, no_grphx)
285  ::setcoordfrom(output, lhs, rhs,
286  new_state, new_pair.first, new_pair.second);
287 # undef if_
288 # undef eq_
289  }
290 
291  // initialize queue with all pairs of intials states from @c lhs and @c rhs
292  inline void
293  initialize_queue (output_t& output,
294  const lhs_t& lhs,
295  const rhs_t& rhs,
296  pair_map_t& m)
297  {
298  for_all_const_initial_states(lhs_s, lhs)
299  for_all_const_initial_states(rhs_s, rhs)
300  {
301  const pair_hstate_t new_pair(*lhs_s, *rhs_s);
302  const hstate_t new_state = output.add_state();
303 
304  this->add_state_to_process(output, lhs, rhs, m, new_state, new_pair);
305  }
306  }
307 
308  inline bool
309  is_shuffle_not_null (const lhs_t& lhs,
310  const rhs_t& rhs,
311  const typename lhs_t::delta_iterator& l,
312  const typename rhs_t::delta_iterator& r,
313  series_set_elt_t& prod_series) const
314  {
315  const series_set_elt_t left_series = lhs.series_of(*l);
316  const series_set_elt_t right_series = rhs.series_of(*r);
317 
318  bool prod_is_not_null = false;
319  for_all_(support_t, supp, left_series.supp())
320  {
321  const monoid_elt_t supp_elt (monoid_, *supp);
322  const semiring_elt_t l = left_series.get(supp_elt);
323  const semiring_elt_t r = right_series.get(supp_elt);
324  const semiring_elt_t p = l * r;
325  if (p != semiring_zero_)
326  {
327  prod_series.assoc(*supp, p.value());
328  prod_is_not_null = true;
329  }
330  }
331  return (prod_is_not_null);
332  }
333 
334  // If set to true, <geometry> tags of the result automaton should be filled
335  const bool use_geometry_;
336 
337  // keep traces of new states created
338  visited_t visited_;
339  // @c to_process_ stores all states of output that needs are not
340  std::queue<pair_hstate_t> to_process_;
341 
342  // frequently used objects in computation
343  const series_set_t& series_;
344  const monoid_t& monoid_;
345  // This variable's type must not be set to a reference.
346  const semiring_elt_t semiring_zero_;
347 };
348 
349 /*-----------.
350 | Wrappers. |
351 `-----------*/
352 
353 template<typename A, typename T, typename U>
354 Element<A, T>
355 shuffle (const Element<A, T>& lhs, const Element<A, U>& rhs,
356  std::map<typename T::hstate_t,
357  std::pair<typename T::hstate_t, typename U::hstate_t> >& m,
358  const bool use_geometry)
359 {
360  Element<A, T> ret(rhs.structure());
361  Shuffle<A, T, U> do_shuffle(ret.structure(), use_geometry);
362  return do_shuffle (ret, lhs, rhs, m);
363 }
364 
365 template<typename A, typename T, typename U>
366 Element<A, T>
367 shuffle (const Element<A, T>& lhs, const Element<A, U>& rhs,
368  const bool use_geometry)
369 {
370  std::map<typename T::hstate_t,
371  std::pair<typename T::hstate_t, typename U::hstate_t> > m;
372  return shuffle (lhs, rhs, m, use_geometry);
373 }
374 
375 } // End of namespace vcsn.
376 
377 #endif // ! VCSN_ALGORITHMS_SHUFFLE_HXX