Vcsn  2.8
Be Rational
epsilon-remover-separate_BACKUP_35473.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <stdexcept>
4 #include <type_traits>
5 #include <unordered_map>
6 #include <unordered_set>
7 #include <utility>
8 #include <vector>
9 
10 #include <vcsn/algos/copy.hh>
11 #include <vcsn/algos/dot.hh>
12 #include <vcsn/algos/fwd.hh>
13 #include <vcsn/core/kind.hh>
14 #include <vcsn/misc/debug-level.hh>
15 #include <vcsn/misc/direction.hh>
18 
19 #undef STATS
20 
21 namespace vcsn
22 {
23  namespace detail
24  {
29  template <Automaton Aut,
30  bool has_one = labelset_t_of<Aut>::has_one()>
31  class epsilon_remover_separate
32  {
33  using automaton_t = std::remove_cv_t<Aut>;
35  using weight_t = typename weightset_t::value_t;
37 
44 
51 
52  public:
56  epsilon_remover_separate(const automaton_t& aut, bool prune = true)
57  : debug_(debug_level())
58  , ws_(*aut->weightset())
59  , prune_(prune)
60  , d2p_(states_size(aut),
61  aut_proper_t::element_type::null_state())
62  , p2d_(states_size(aut),
63  aut_dirty_t::element_type::null_state())
64  {
65 <<<<<<< HEAD
66  auto dirty_ctx = dirty_ctx_t{{}, ws_};
67  auto proper_ctx = aut->context();
68 =======
69  const auto dirty_ctx = dirty_ctx_t{{}, ws_};
70  const auto proper_ctx = make_proper_context(aut->context());
71 >>>>>>> master
72  aut_dirty_ = make_shared_ptr<aut_dirty_t>(dirty_ctx);
73  aut_proper_ = make_shared_ptr<aut_proper_t>(proper_ctx);
74 
75  auto pcopier = make_copier(aut, aut_proper_);
76  auto dcopier = make_copier(aut, aut_dirty_);
77 
78  using state_t = state_t_of<automaton_t>;
79  using transition_t = transition_t_of<automaton_t>;
80  pcopier([](state_t) { return true; },
81  [&aut](transition_t t) {
82  return !aut->labelset()->is_one(aut->label_of(t));
83  }
84  );
85  dcopier([&aut](state_t s) {
86  return (!in(aut, s, aut->labelset()->one()).empty()
87  || !out(aut, s, aut->labelset()->one()).empty());
88  },
89  [&aut](transition_t t) {
90  return aut->labelset()->is_one(aut->label_of(t));
91  }
92  );
93 
94  const auto& dorigins = dcopier.state_map();
95  const auto& porigins = pcopier.state_map();
96  for (const auto& dp : dorigins)
97  {
98  const auto pp = porigins.find(dp.first);
99  assert(pp != porigins.end());
100  d2p_[dp.second] = pp->second;
101  p2d_[pp->second] = dp.second;
102  }
103  }
104 
105  private:
108 
111  {
112  auto dirty_s = p2d_[proper_s];
113  if (auto p = profile_(proper_s))
114  {
115  auto in_dirty = in(aut_dirty_, dirty_s).size();
116  auto in_proper = in(aut_proper_, proper_s).size();
117  auto out_dirty = out(aut_dirty_, dirty_s).size();
118  auto out_proper = all_out(aut_proper_, proper_s).size();
119 
120  p->update(in_dirty, in_proper + in_dirty,
121  out_dirty, out_proper + out_dirty);
122  }
123  }
124 
127  void build_heap_()
128  {
129  for (auto s: aut_dirty_->states())
130  // We don't care about states without incoming spontaneous
131  // transitions.
132  if (in(aut_dirty_, s).size())
133  {
134  auto proper_s = d2p_[s];
135  auto h = todo_.emplace(profile_t{proper_s, 0, 0, 0, 0});
136  handles_.emplace(proper_s, h);
137  update_profile_(proper_s);
138  }
139  }
140 
142  void show_heap_() const
143  {
144  const char* sep = "";
145  for (auto i = todo_.ordered_begin(), end = todo_.ordered_end();
146  i != end; ++i)
147  {
148  std::cerr << sep << *i;
149  sep = " > ";
150  }
151  }
152 
156  {
157  if (3 < debug_)
158  {
159  std::cerr << "update heap (" << s << " : ";
160  show_heap_();
161  }
162  auto i = handles_.find(s);
163  if (i != handles_.end())
164  todo_.update(i->second);
165  if (3 < debug_)
166  {
167  std::cerr << ") => ";
168  show_heap_();
169  std::cerr << '\n';
170  }
171  }
172 
173 #ifdef STATS
174  unsigned added_ = 0;
175  unsigned removed_ = 0;
176 #endif
177 
181  {
182  auto i = handles_.find(s);
183  if (i == handles_.end())
184  return nullptr;
185  else
186  return &*i->second;
187  }
188 
200  void remover_on(state_proper_t proper_s, state_dirty_t dirty_s)
201  {
202  // The star of the weight of the loop on 's' (1 if no loop).
203  weight_t star = ws_.one();
204  using state_weight_t = std::pair<state_dirty_t, weight_t>;
205  auto closure = std::vector<state_weight_t>{};
206 
207 #ifdef STATS
208  // Number of transitions that will be removed.
209  auto removed = in(aut_dirty_, dirty_s).size();
210 #endif
211  // Iterate on a copy: we remove these transitions in the loop.
212  for (auto t : make_vector(in(aut_dirty_, dirty_s)))
213  {
214  weight_t weight = aut_dirty_->weight_of(t);
215  auto src = aut_dirty_->src_of(t);
216  if (src == dirty_s) //loop
217  star = ws_.star(weight);
218  else
219  closure.emplace_back(src, weight);
220  // Delete incoming epsilon transitions.
221  aut_dirty_->del_transition(t);
222  }
223 
224  /*
225  For each transition (t : s -- label|weight --> dst),
226  for each former
227  epsilon transition closure->first -- e|closure->second --> s
228  a transition
229  (closure->first -- label | closure->second*weight --> dst)
230  is added to the automaton (add, not set !!)
231 
232  If (s) is final with weight (weight),
233  for each former
234  epsilon transition closure->first -- e|closure->second --> s
235  pair-second * weight is added to the final weight
236  of closure->first
237  */
238 
239 
240  // TODO: factoring with lambda
241  for (auto t: out(aut_dirty_, dirty_s))
242  {
243  weight_t blow = ws_.mul(star, aut_dirty_->weight_of(t));
244  aut_dirty_->set_weight(t, blow);
245 
246  auto dst = aut_dirty_->dst_of(t);
247  for (auto pair: closure)
248  {
249  auto src = pair.first;
250  weight_t w = ws_.mul(pair.second, blow);
251  aut_dirty_->add_transition(src, dst, {}, w);
252  }
253  }
254 
255  for (auto t: all_out(aut_proper_, proper_s))
256  {
257  weight_t blow = ws_.mul(star, aut_proper_->weight_of(t));
258  aut_proper_->set_weight(t, blow);
259 
260  label_proper_t label = aut_proper_->label_of(t);
261  auto dst = aut_proper_->dst_of(t);
262  for (auto pair: closure)
263  {
264  auto src = pair.first;
265  weight_t w = ws_.mul(pair.second, blow);
266  aut_proper_->add_transition(d2p_[src], dst, label, w);
267  }
268  }
269 #ifdef STATS
270  // Number of transition that have been added.
271  auto added = (all_out(aut_proper_, proper_s).size()
272  + out(aut_dirty_, dirty_s).size()) * closure.size();
273 #endif
274  if (prune_
275  && in(aut_dirty_, dirty_s).empty()
276  && all_in(aut_proper_, proper_s).empty())
277  {
278 #ifdef STATS
279  removed += (all_out(aut_proper_, proper_s).size()
280  + out(aut_dirty_, dirty_s).size());
281 #endif
282  aut_proper_->del_state(proper_s);
283  aut_dirty_->del_state(dirty_s);
284  }
285 #ifdef STATS
286  added_ += added;
287  removed_ += removed;
288  if (1 < debug_)
289  std::cerr << " -" << removed << "+" << added
290  << " (-" << removed_ << "+" << added_ << ")";
291 #endif
292  }
293 
294  public:
297  {
298  state_dirty_t dirty_s = p2d_[proper_s];
299  if (dirty_s == aut_dirty_->null_state())
300  return false;
301  else
302  return !in(aut_dirty_, dirty_s).empty();
303  }
304 
306  void remover_on(state_proper_t proper_s)
307  {
308  state_dirty_t dirty_s = p2d_[proper_s];
309  if (dirty_s != aut_dirty_->null_state())
310  remover_on(proper_s, dirty_s);
311  }
312 
326  {
327  if (4 < debug_)
328  {
329  dot(aut_proper_, std::cerr) << '\n';
330  dot(aut_dirty_, std::cerr) << '\n';
331  }
332  build_heap_();
333  /* For each state (s), for each incoming epsilon-transitions
334  (t), if (t) is a loop, the star of its weight is computed,
335  otherwise, (t) is stored into the closure list. Then (t)
336  is removed. */
337 
338  // The neighbors of s: their profiles need to be updated after
339  // s was processed.
340  auto neighbors = std::unordered_set<state_proper_t>{};
341  while (!todo_.empty())
342  {
343  if (2 < debug_)
344  {
345  std::cerr << "Before: ";
346  show_heap_();
347  std::cerr << '\n';
348  }
349  auto p = todo_.top();
350  todo_.pop();
351  if (1 < debug_)
352  std::cerr << "Remove: " << p;
353 
354  state_proper_t proper_s = p.state;
355  auto dirty_s = p2d_[proper_s];
356  handles_.erase(proper_s);
357 
358  // Adjacent states.
359  neighbors.clear();
360  for (auto t: in(aut_proper_, proper_s))
361  if (aut_proper_->src_of(t) != proper_s)
362  neighbors.emplace(aut_proper_->src_of(t));
363  for (auto t: out(aut_proper_, proper_s))
364  if (aut_proper_->dst_of(t) != proper_s)
365  neighbors.emplace(aut_proper_->dst_of(t));
366 
367  if (dirty_s != aut_dirty_->null_state())
368  {
369  state_dirty_t n;
370  for (auto t: in(aut_dirty_, dirty_s))
371  if ((n = aut_dirty_->src_of(t)) != dirty_s)
372  neighbors.emplace(d2p_[n]);
373  for (auto t: out(aut_dirty_, dirty_s))
374  if ((n = aut_dirty_->dst_of(t)) != dirty_s)
375  neighbors.emplace(d2p_[n]);
376 
377  remover_on(proper_s, dirty_s);
378  }
379 
380  // Update all neighbors and then the heap.
381  for (auto n: neighbors)
382  update_profile_(n);
383  for (auto n: neighbors)
384  update_heap_(n);
385  if (1 < debug_)
386  std::cerr << " #tr: "
387  << transitions(aut_dirty_).size()
388  << "/" << (transitions(aut_dirty_).size()
389  + transitions(aut_proper_).size())
390  << '\n';
391  if (2 < debug_)
392  {
393  std::cerr << "After: ";
394  show_heap_();
395  std::cerr << '\n';
396  }
397  if (4 < debug_)
398  {
399  dot(aut_proper_, std::cerr) << '\n';
400  dot(aut_dirty_, std::cerr) << '\n';
401  }
402  if (2 < debug_)
403  std::cerr << '\n';
404  }
405 #ifdef STATS
406  if (0 < debug_)
407  std::cerr << "Total transitions -" << removed_
408  << "+" << added_ << '\n';
409 #endif
410 
411  return aut_proper_;
412  }
413 
416  {
417  return aut_proper_;
418  }
419 
420  private:
422  int debug_;
423 
427 
431 
433  const weightset_t& ws_;
434 
437  heap_t todo_;
439  std::unordered_map<state_proper_t, typename heap_t::handle_type> handles_;
440 
442  bool prune_;
443 
445  std::vector<state_proper_t> d2p_;
447  std::vector<state_dirty_t> p2d_;
448  };
449 
452  template <Automaton Aut>
453  class epsilon_remover_separate<Aut, false>
454  {
455  using automaton_t = std::remove_cv_t<Aut>;
457  public:
459  : aut_(aut)
460  {}
461 
463  {
464  return copy(aut_);
465  }
466 
468  {
469  return aut_;
470  }
471 
472  private:
473  automaton_t aut_;
474  };
475  }
476 } // namespace vcsn
std::shared_ptr< detail::mutable_automaton_impl< Context > > mutable_automaton
Definition: fwd.hh:25
void remover_on(state_proper_t proper_s)
Wrapper around remover_on() which does a lookup of the dirty state.
void remover_on(state_proper_t proper_s, state_dirty_t dirty_s)
For each state (s), for each incoming epsilon-transitions (t), if (t) is a loop, the star of its weig...
typename detail::weightset_t_of_impl< base_t< ValueSet > >::type weightset_t_of
Definition: traits.hh:67
bool prune_
Whether to prune states that become inaccessible.
epsilon_remover_separate(const automaton_t &aut, bool prune=true)
Get ready to eliminate spontaneous transitions.
aut_dirty_t aut_dirty_
The sponteanous part.
typename detail::transition_t_of_impl< base_t< ValueSet > >::type transition_t_of
Definition: traits.hh:65
typename detail::state_t_of_impl< base_t< ValueSet > >::type state_t_of
Definition: traits.hh:64
size_t states_size(const Aut &aut)
The largest state number, plus one.
Definition: automaton.hh:41
std::vector< state_proper_t > d2p_
dirty states -> proper states.
profile_t * profile_(state_proper_t s) const
The profile of state s, or nullptr if it is not to be processed.
std::vector< typename Cont::value_type > make_vector(const Cont &cont)
The content of cont as a vector.
Definition: vector.hh:18
This class contains the core of the proper algorithm.
void build_heap_()
Build the profiles and the heap for states with incoming spontaneous transitions. ...
vcsn::min_fibonacci_heap< profile_t > heap_t
Min-heap to decide the order of state-elimination.
auto all_in(const Aut &aut, state_t_of< Aut > s)
Indexes of transitions entering state s.
Definition: automaton.hh:116
aut_proper_t get_proper()
Return the proper part. Needed by lazy algorithm.
auto all_out(const Aut &aut, state_t_of< Aut > s)
Indexes of transitions leaving state s.
Definition: automaton.hh:67
typename detail::context_t_of_impl< base_t< ValueSet > >::type context_t_of
Definition: traits.hh:61
const weightset_t & ws_
Shorthand to the weightset.
pair_automaton< Aut > pair(const Aut &aut, bool keep_initials=false)
Definition: pair.hh:252
auto copy(const AutIn &input, KeepState keep_state, KeepTrans keep_trans) -> decltype(keep_state(input->null_state()), keep_trans(input->null_transition()), make_fresh_automaton< AutIn, AutOut >(input))
A copy of input keeping only its states that are accepted by keep_state, and transitions accepted by ...
Definition: copy.hh:322
typename detail::labelset_t_of_impl< base_t< ValueSet > >::type labelset_t_of
Definition: traits.hh:63
std::ostream & dot(const Aut &aut, std::ostream &out=std::cout, format fmt={}, bool mathjax=false)
Print an automaton in Graphviz&#39;s Dot format.
Definition: dot.hh:435
aut_proper_t operator()()
Remove all the states with incoming spontaneous transitions.
void update_profile_(state_proper_t proper_s)
Update the profile of s.
Definition: a-star.hh:8
auto in(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions arriving to state s.
Definition: automaton.hh:135
mutable_automaton< dirty_ctx_t > aut_dirty_t
Spontaneous automaton.
void update_heap_(state_proper_t s)
Update the heap for s.
typename detail::label_t_of_impl< base_t< ValueSet > >::type label_t_of
Definition: traits.hh:62
This is used by some epsilon removal algorithms.
detail::copier< AutIn, AutOut > make_copier(const AutIn &in, AutOut &out, bool safe=true)
Build an automaton copier.
Definition: copy.hh:256
std::unordered_map< state_proper_t, typename heap_t::handle_type > handles_
Map: state -> heap-handle.
fresh_automaton_t_of< Aut, proper_ctx_t > aut_proper_t
Proper automaton.
void show_heap_() const
Show the heap, for debugging.
boost::heap::fibonacci_heap< Elt, detail::comparator_t< Elt > > min_fibonacci_heap
value_impl< detail::label_tag > label
Definition: fwd.hh:32
int debug_
Debug level. The higher, the more details are reported.
std::vector< state_dirty_t > p2d_
proper states -> dirty states.
#define Automaton
Definition: automaton.hh:23
static int debug_level()
Debug level set in the user&#39;s environment.
Definition: debug-level.hh:11
auto transitions(const Aut &aut) -> decltype(all_transitions(aut, is_special_t< Aut >
All the transition indexes between visible states.
Definition: automaton.hh:248
auto make_proper_context(const context< LabelSet, WeightSet > &ctx) -> proper_context< context< LabelSet, WeightSet >>
From a context, its non-nullable context.
Definition: labelset.hh:216
bool state_has_spontaneous_in(state_proper_t proper_s) const
Whether the given state has incoming spontaneous transitions.
typename Aut::element_type::template fresh_automaton_t< Context > fresh_automaton_t_of
Given an automaton type, the type of its copies.
Definition: traits.hh:82
value_impl< detail::weight_tag > weight
Definition: fwd.hh:34
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:86