Vaucanson  1.4.1
eps_removal_sp.hxx
1 // eps_removal_sp.hxx: this file is part of the Vaucanson project.
2 //
3 // Vaucanson, a generic library for finite state machines.
4 //
5 // Copyright (C) 2004, 2005, 2006, 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_EPS_REMOVAL_SP_HXX
18 # define VCSN_ALGORITHMS_EPS_REMOVAL_SP_HXX
19 
21 
22 # include <vaucanson/automata/concept/automata_base.hh>
23 # include <vaucanson/misc/usual_macros.hh>
24 
25 # include <boost/multi_index_container.hpp>
26 # include <boost/multi_index/member.hpp>
27 # include <boost/multi_index/hashed_index.hpp>
28 # include <boost/multi_index/composite_key.hpp>
29 # include <boost/functional/hash/hash.hpp>
30 # include <boost/tuple/tuple.hpp>
31 # include <vector>
32 # include <list>
33 # include <queue>
34 # include <map>
35 # include <utility>
36 # include <set>
37 # include <stack>
38 
39 namespace vcsn {
40 
41  /*----------------------------------------.
42  | EpsilonRemoverSp for weighted automaton |
43  `----------------------------------------*/
44 
45  template
46  <class A_, typename Auto, typename Weight>
47  class EpsilonRemoverSp
48  {
49  AUTOMATON_TYPES(Auto);
50  public:
51  struct tr_t
52  {
53  tr_t(hstate_t src_, hstate_t dst_, series_set_elt_t series_)
54  : src(src_),
55  dst(dst_),
56  series(series_)
57  {}
58 
59  hstate_t src;
60  hstate_t dst;
61  series_set_elt_t series;
62  };
63 
64  struct s_shortest
65  {
66  s_shortest(const hstate_t src_, const hstate_t dst_, semiring_elt_t& d_, semiring_elt_t& r_)
67  : src(src_),
68  dst(dst_),
69  dist(d_),
70  rel(r_)
71  {}
72 
73  const hstate_t src;
74  const hstate_t dst;
75  semiring_elt_t dist;
76  semiring_elt_t rel;
77  };
78 
79  struct change_rel
80  {
81  change_rel(const semiring_elt_t& new_rel)
82  : new_rel(new_rel)
83  {}
84 
85  void operator() (s_shortest& s)
86  {
87  s.rel = new_rel;
88  }
89  private:
90  semiring_elt_t new_rel;
91  };
92 
93  struct change_dist
94  {
95  change_dist(const semiring_elt_t& new_dist)
96  : new_dist(new_dist)
97  {}
98 
99  void operator() (s_shortest& s)
100  {
101  s.dist = new_dist;
102  }
103  private:
104  semiring_elt_t new_dist;
105  };
106 
107  struct add_dr
108  {
109  add_dr(const semiring_elt_t& new_dist, const semiring_elt_t& new_rel)
110  : new_dist(new_dist),
111  new_rel(new_rel)
112  {}
113 
114  void operator() (s_shortest& s)
115  {
116  s.dist += new_dist;
117  s.rel += new_rel;
118  }
119  private:
120  semiring_elt_t new_dist;
121  semiring_elt_t new_rel;
122  };
123 
124  typedef boost::multi_index_container
125  <
126  s_shortest,
127  boost::multi_index::indexed_by
128  <
129  boost::multi_index::hashed_unique
130  <
131  boost::multi_index::composite_key
132  <
133  s_shortest,
134  BOOST_MULTI_INDEX_MEMBER(s_shortest, const hstate_t, src),
135  BOOST_MULTI_INDEX_MEMBER(s_shortest, const hstate_t, dst)
136  >
137  >
138  >
139  > s_shortest_hash;
140 
141  EpsilonRemoverSp(const AutomataBase<A_>&,
142  Auto& aut)
143  : a(aut),
144  null_series(aut.series().zero_),
145  semiring_elt_zero(aut.series().semiring().wzero_),
146  semiring_elt_one(aut.series().semiring().wone_),
147  monoid_identity(aut.series().monoid().VCSN_EMPTY_)
148  {
149  shortest_eps_distance();
150  }
151 
152  void operator() (misc::direction_type dir)
153  {
154  // Remove epsilon-transitions
155  for_all_transitions(e,a)
156  {
157  series_set_elt_t t = a.series_of(*e);
158  if (t.get(monoid_identity) != semiring_elt_zero)
159  {
160  t.assoc(monoid_identity.value(), semiring_elt_zero.value());
161  if (t != null_series)
162  a.add_series_transition(a.src_of(*e), a.dst_of(*e), t);
163  a.del_transition(*e);
164  }
165  }
166 
167  if (dir == misc::backward)
168  backward_remove();
169  else
170  forward_remove();
171  }
172 
173  private:
174  void shortest_eps_distance()
175  {
176  for_all_const_states(s, a)
177  {
178  typename s_shortest_hash::iterator it;
179  shortest_hash.insert(s_shortest(*s, *s, semiring_elt_one, semiring_elt_one));
180  squeue.insert(*s);
181  while (!squeue.empty())
182  {
183  hstate_t curr = *squeue.begin();
184  squeue.erase(squeue.begin());
185  semiring_elt_t R = semiring_elt_zero;
186  it = shortest_hash.find(boost::make_tuple(*s, curr));
187  if (it != shortest_hash.end())
188  {
189  R = it->rel;
190  shortest_hash.modify(it, change_rel(semiring_elt_zero));
191  }
192 
193  for (delta_iterator e(a.value(), curr); ! e.done(); e.next())
194  if (a.is_spontaneous(*e))
195  {
196  semiring_elt_t dist = semiring_elt_zero;
197  it = shortest_hash.find(boost::make_tuple(*s, a.dst_of(*e)));
198  if (it != shortest_hash.end())
199  dist = it->dist;
200  semiring_elt_t we = a.series_of(*e).get(monoid_identity);
201  we = R * we;
202  if (dist != dist + we)
203  {
204  if (it != shortest_hash.end())
205  {
206  shortest_hash.modify(it, add_dr(we, we));
207  squeue.insert(a.dst_of(*e));
208  }
209  else
210  {
211  shortest_hash.insert(s_shortest(*s, a.dst_of(*e), we, we));
212  squeue.insert(a.dst_of(*e));
213  }
214  }
215  }
216  }
217  }
218  }
219 
220  void backward_remove()
221  {
222  std::list<std::pair<htransition_t, semiring_elt_t> > tr_l;
223  std::list<std::pair<hstate_t, semiring_elt_t> > fin_l;
224  std::stack<tr_t> tr_st;
225  std::stack<std::pair<hstate_t, series_set_elt_t> > fin_st;
226 
227  for_all_(s_shortest_hash, it, shortest_hash)
228  if (it->src != it->dst)
229  {
230  for (delta_iterator e(a.value(), it->dst); ! e.done(); e.next())
231  tr_st.push(tr_t(it->src, a.dst_of(*e), it->dist * a.series_of(*e)));
232  if (a.is_final(it->dst))
233  fin_st.push(make_pair(it->src, it->dist * a.get_final(it->dst)));
234  }
235  else
236  {
237  if (it->dist != semiring_elt_one)
238  {
239  for (delta_iterator e(a.value(), it->dst); ! e.done(); e.next())
240  tr_l.push_front(std::pair<htransition_t, semiring_elt_t>(*e, it->dist)); // associate each e with it->dist
241  if (a.is_final(it->dst))
242  fin_l.push_front(std::pair<hstate_t, semiring_elt_t>(it->src, it->dist));// store what we need to multiply w(final(it->src)) by it->dist
243  }
244  }
245 
246  for (typename std::list<std::pair<htransition_t, semiring_elt_t> >::iterator it = tr_l.begin();
247  it != tr_l.end(); ++it)
248  {
249  series_set_elt_t s = a.series_of(it->first) * it->second;
250  if (s != null_series)
251  a.add_series_transition(a.src_of(it->first), a.dst_of(it->first), s);
252  a.del_transition(it->first);
253  }
254 
255  for (typename std::list<std::pair<hstate_t, semiring_elt_t> >::iterator it = fin_l.begin();
256  it != fin_l.end(); ++it)
257  a.set_final(it->first, it->second * a.get_final(it->first));
258 
259  while (!tr_st.empty())
260  {
261  a.add_series_transition(tr_st.top().src, tr_st.top().dst, tr_st.top().series);
262  tr_st.pop();
263  }
264 
265  while (!fin_st.empty())
266  {
267  a.set_final(fin_st.top().first, a.get_final(fin_st.top().first) +
268  fin_st.top().second);
269  fin_st.pop();
270  }
271  }
272 
273  void forward_remove()
274  {
275  std::list<std::pair<htransition_t, semiring_elt_t> > tr_l;
276  std::list<std::pair<hstate_t, semiring_elt_t> > fin_l;
277  std::stack<tr_t> tr_st;
278  std::stack<std::pair<hstate_t, series_set_elt_t> > init_st;
279 
280  for_all_(s_shortest_hash, it, shortest_hash)
281  if (it->src != it->dst)
282  {
283  for (rdelta_iterator e(a.value(), it->dst); ! e.done(); e.next())
284  tr_st.push(tr_t(a.src_of(*e), it->dst, a.series_of(*e) * it->dist));
285  if (a.is_initial(it->src))
286  init_st.push(make_pair(it->dst, a.get_initial(it->src) * it->dist));
287  }
288  else
289  {
290  if (it->dist != semiring_elt_one)
291  {
292  for (rdelta_iterator e(a.value(), it->dst); ! e.done(); e.next())
293  tr_l.push_front(std::pair<htransition_t, semiring_elt_t>(*e, it->dist)); // associate each e with it->dist
294  if (a.is_initial(it->src))
295  fin_l.push_front(std::pair<hstate_t, semiring_elt_t>(it->dst, it->dist));// store what we need to multiply w(final(it->src)) by it->dist
296  }
297  }
298 
299  for (typename std::list<std::pair<htransition_t, semiring_elt_t> >::iterator it = tr_l.begin();
300  it != tr_l.end(); ++it)
301  {
302  series_set_elt_t s = a.series_of(it->first) * it->second;
303  if (s != null_series)
304  a.add_series_transition(a.src_of(it->first), a.dst_of(it->first), s);
305  a.del_transition(it->first);
306  }
307 
308  for (typename std::list<std::pair<hstate_t, semiring_elt_t> >::iterator it = fin_l.begin();
309  it != fin_l.end(); ++it)
310  a.set_initial(it->first, it->second * a.get_initial(it->first));
311 
312  while (!tr_st.empty())
313  {
314  a.add_series_transition(tr_st.top().src, tr_st.top().dst, tr_st.top().series);
315  tr_st.pop();
316  }
317 
318  while (!init_st.empty())
319  {
320  a.set_initial(init_st.top().first, a.get_initial(init_st.top().first) +
321  init_st.top().second);
322  init_st.pop();
323  }
324  }
325 
326  automaton_t& a;
327 
328  // zero and identity of used algebraic structure.
329  series_set_elt_t null_series;
330  semiring_elt_t semiring_elt_zero;
331  semiring_elt_t semiring_elt_one;
332  monoid_elt_t monoid_identity;
333 
334  // Shortest distance structures
335  s_shortest_hash shortest_hash;
336  std::set<hstate_t> squeue;
337  };
338 
339  /*--------------.
340  | eps_removal. |
341  `--------------*/
342 
343  template<class A_, typename Auto, typename Weight>
344  void
345  do_eps_removal_here_sp(const AutomataBase<A_>& a_set,
346  const Weight&,
347  Auto& a,
349  {
350  BENCH_TASK_SCOPED("eps_removal");
351 
352  EpsilonRemoverSp<A_, Auto, Weight> algo(a_set, a);
353  algo(dir);
354  }
355 
356  template<typename A, typename AI>
357  void
359  {
360  typedef Element<A, AI> automaton_t;
361  AUTOMATON_TYPES(automaton_t);
362 
363  do_eps_removal_here_sp(a.structure(),
364  SELECT(semiring_elt_value_t),
365  a, dir);
366  }
367 
368  template<typename A, typename AI>
369  Element<A, AI>
371  {
372  typedef Element<A, AI> automaton_t;
373  AUTOMATON_TYPES(automaton_t);
374 
375  automaton_t ret(a);
376  do_eps_removal_here_sp(ret.structure(),
377  SELECT(semiring_elt_value_t),
378  ret, dir);
379  return ret;
380  }
381 
382  template<typename A, typename AI>
383  void
385  {
386  typedef Element<A, AI> automaton_t;
387  AUTOMATON_TYPES(automaton_t);
388 
389  do_eps_removal_here_sp(a.structure(),
390  SELECT(semiring_elt_value_t),
391  a, misc::backward);
392  }
393 
394  template<typename A, typename AI>
395  Element<A, AI>
397  {
398  typedef Element<A, AI> automaton_t;
399  AUTOMATON_TYPES(automaton_t);
400 
401  automaton_t ret(a);
402  do_eps_removal_here_sp(ret.structure(),
403  SELECT(semiring_elt_value_t),
404  ret, misc::backward);
405  return ret;
406  }
407 
408  template<typename A, typename AI>
409  void
411  {
412  typedef Element<A, AI> automaton_t;
413  AUTOMATON_TYPES(automaton_t);
414 
415  do_eps_removal_here_sp(a.structure(),
416  SELECT(semiring_elt_value_t),
417  a, misc::forward);
418  }
419 
420  template<typename A, typename AI>
421  Element<A, AI>
423  {
424  typedef Element<A, AI> automaton_t;
425  AUTOMATON_TYPES(automaton_t);
426 
427  automaton_t ret(a);
428  do_eps_removal_here_sp(ret.structure(),
429  SELECT(semiring_elt_value_t),
430  ret, misc::forward);
431  return ret;
432  }
433 
434 } // vcsn
435 
436 #endif // ! VCSN_ALGORITHMS_EPS_REMOVAL_HXX