Vaucanson  1.4.1
product.hxx
1 // product.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 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_PRODUCT_HXX
18 # define VCSN_ALGORITHMS_PRODUCT_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 product algorithm. |
41 `--------------------------------*/
42 template<typename A, typename T, typename U>
43 class Product
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  Product (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 product 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("product");
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  series_set_elt_t prod_series(series_);
88  if (is_product_not_null(lhs.get_initial(lhs_s), rhs.get_initial(rhs_s), prod_series))
89  output.set_initial(current_state, prod_series);
90  }
91  {
92  series_set_elt_t prod_series(series_);
93  if (is_product_not_null(lhs.get_final(lhs_s), rhs.get_final(rhs_s), prod_series))
94  output.set_final(current_state, prod_series);
95  }
96  for (typename lhs_t::delta_iterator l(lhs.value(), lhs_s);
97  ! l.done();
98  l.next())
99  for (typename rhs_t::delta_iterator r(rhs.value(), rhs_s);
100  ! r.done();
101  r.next())
102  {
103  series_set_elt_t prod_series(series_);
104 
105  if (is_product_not_null(lhs.series_of(*l), rhs.series_of(*r), prod_series))
106  {
107  const pair_hstate_t new_pair(lhs.dst_of(*l), rhs.dst_of(*r));
108  typename visited_t::const_iterator found = visited_.find(new_pair);
109 
110  hstate_t dst;
111  if (found == visited_.end())
112  {
113  dst = output.add_state();
114 
115  this->add_state_to_process(output, lhs, rhs, m, dst, new_pair);
116  }
117  else
118  dst = found->second;
119  output.add_series_transition(current_state, dst, prod_series);
120  }
121  }
122  }
123  return output;
124  }
125 
126  private:
127  // Some little graphic tools
128  class grphx
129  {
130  public:
131  template <typename Output, typename Lhs, typename Rhs>
132  static void
133  setcoordfrom (Output& a,
134  const Lhs& lhs,
135  const Rhs& rhs,
136  const typename Output::hstate_t state,
137  const typename Lhs::hstate_t x_state,
138  const typename Rhs::hstate_t y_state)
139  {
140  typename std::map<typename Lhs::hstate_t,
141  typename Lhs::geometry_t::coords_t>::const_iterator iter;
142  typename std::map<typename Rhs::hstate_t,
143  typename Rhs::geometry_t::coords_t>::const_iterator iter2;
144  double x = 0, y = 0;
145 
146  iter = lhs.geometry().states().find(x_state);
147  if (iter != lhs.geometry().states().end())
148  x = iter->second.first;
149 
150  iter2 = rhs.geometry().states().find(y_state);
151  if (iter2 != rhs.geometry().states().end())
152  y = iter2->second.second;
153 
154  a.geometry().states()[state] = std::make_pair(x, y);
155  }
156  private:
157  // Diagonal alignement with a depth-first traversal
158  template<typename I>
159  void
160  align (const I& a)
161  {
162  AUTOMATON_TYPES(I);
163  std::map<hstate_t,bool> visited;
164  std::stack<hstate_t> stack;
165 
166  for_all_const_states(i, a)
167  {
168  visited[*i] = false;
169  // ensure inaccessible states will be visited
170  stack.push(*i);
171  }
172 
173  for_all_const_initial_states(i, a)
174  stack.push(*i);
175 
176  int x = 0;
177  while (!stack.empty())
178  {
179  hstate_t i = stack.top();
180  stack.pop();
181 
182  if (!visited[i])
183  {
184  visited[i] = true;
185 
186  a.geometry()[i] = std::make_pair(x, x);
187  x++;
188 
189  for (delta_iterator j(a.value(), i);
190  ! j.done();
191  j.next())
192  stack.push(a.dst_of(*j));
193  }
194  }
195  }
196 
197  };
198  class no_grphx
199  {
200  public:
201  template <typename Output, typename Lhs, typename Rhs>
202  static void
203  setcoordfrom (Output& a,
204  const Lhs& lhs,
205  const Rhs& rhs,
206  const typename Output::hstate_t state,
207  const typename Lhs::hstate_t x_state,
208  const typename Rhs::hstate_t y_state) {};
209  };
210 
211  // useful typedefs
212  AUTOMATON_TYPES(output_t);
213 
214  typedef std::pair<typename lhs_t::hstate_t, typename rhs_t::hstate_t>
215  pair_hstate_t;
216  typedef std::list<htransition_t> delta_ret_t;
217  typedef std::map<pair_hstate_t, hstate_t> visited_t;
218  typedef typename series_set_elt_t::support_t support_t;
219 
220  // add a @c new_state in the queue
221  inline void
222  add_state_to_process (output_t& output,
223  const lhs_t& lhs,
224  const rhs_t& rhs,
225  pair_map_t& m,
226  const hstate_t& new_state,
227  const pair_hstate_t& new_pair)
228  {
229  m[new_state] = new_pair;
230  visited_[new_pair] = new_state;
231  to_process_.push(new_pair);
232 
233 # define if_(Cond, ThenClause, ElseClause) \
234 misc::static_if_simple<Cond, ThenClause, ElseClause>::t
235 # define eq_(Type1, Type2) \
236 misc::static_eq<Type1, Type2>::value
237 # define DECLARE_GEOMETRY(Type) \
238  typedef geometry<typename Type::hstate_t, typename Type::htransition_t, typename Type::geometry_coords_t> geometry_ ## Type ;
239 
240  DECLARE_GEOMETRY(output_t)
241  DECLARE_GEOMETRY(lhs_t)
242  DECLARE_GEOMETRY(rhs_t)
243  if (use_geometry_)
244  if_(eq_(typename output_t::geometry_t, geometry_output_t) and \
245  eq_(typename rhs_t::geometry_t, geometry_rhs_t) and \
246  eq_(typename lhs_t::geometry_t, geometry_lhs_t), \
247  grphx, no_grphx)
248  ::setcoordfrom(output, lhs, rhs,
249  new_state, new_pair.first, new_pair.second);
250 # undef if_
251 # undef eq_
252  }
253 
254  // initialize queue with all pairs of intials states from @c lhs and @c rhs
255  inline void
256  initialize_queue (output_t& output,
257  const lhs_t& lhs,
258  const rhs_t& rhs,
259  pair_map_t& m)
260  {
261  for_all_const_initial_states(lhs_s, lhs)
262  for_all_const_initial_states(rhs_s, rhs)
263  {
264  const pair_hstate_t new_pair(*lhs_s, *rhs_s);
265  const hstate_t new_state = output.add_state();
266 
267  this->add_state_to_process(output, lhs, rhs, m, new_state, new_pair);
268  }
269  }
270 
271  inline bool
272  is_product_not_null (const series_set_elt_t left_series,
273  const series_set_elt_t right_series,
274  series_set_elt_t& prod_series) const
275  {
276  bool prod_is_not_null = false;
277  //the alphabet of rhs is a subset of the alphbet of rhs
278  //thus, we consider monomials in right_series; they are compatible with lhs.
279  for_all_(support_t, supp, right_series.supp())
280  {
281  const monoid_elt_t supp_elt (monoid_, *supp);
282  const semiring_elt_t l = left_series.get(supp_elt);
283  const semiring_elt_t r = right_series.get(supp_elt);
284  const semiring_elt_t p = l * r;
285  if (p != semiring_zero_)
286  {
287  prod_series.assoc(*supp, p.value());
288  prod_is_not_null = true;
289  }
290  }
291  return (prod_is_not_null);
292  }
293 
294  // If set to true, <geometry> tags of the result automaton should be filled
295  const bool use_geometry_;
296 
297  // keep traces of new states created
298  visited_t visited_;
299  // @c to_process_ stores all states of output that needs are not
300  std::queue<pair_hstate_t> to_process_;
301 
302  // frequently used objects in computation
303  const series_set_t& series_;
304  const monoid_t& monoid_;
305  // This variable's type must not be set to a reference.
306  const semiring_elt_t semiring_zero_;
307 };
308 
309 /*-----------.
310 | Wrappers. |
311 `-----------*/
312 
313 template<typename A, typename T, typename U>
314 Element<A, T>
315 product (const Element<A, T>& lhs, const Element<A, U>& rhs,
316  std::map<typename T::hstate_t,
317  std::pair<typename T::hstate_t, typename U::hstate_t> >& m,
318  const bool use_geometry)
319 {
320  Element<A, T> ret(lhs.structure());
321  Product<A, T, U> do_product(ret.structure(), use_geometry);
322  return do_product (ret, lhs, rhs, m);
323 }
324 
325 template<typename A, typename T, typename U>
326 Element<A, T>
327 product (const Element<A, T>& lhs, const Element<A, U>& rhs,
328  const bool use_geometry)
329 {
330  std::map<typename T::hstate_t,
331  std::pair<typename T::hstate_t, typename U::hstate_t> > m;
332  return product (lhs, rhs, m, use_geometry);
333 }
334 
335 } // End of namespace vcsn.
336 
337 #endif // ! VCSN_ALGORITHMS_PRODUCT_HXX