Vcsn  2.1
Be Rational
scc.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <iterator> // std::rbegin
4 #include <limits>
5 #include <stack>
6 
7 #include <boost/range/rbegin.hpp>
8 #include <boost/range/rend.hpp>
9 
10 #include <vcsn/algos/copy.hh> // make_fresh_automaton
11 #include <vcsn/algos/filter.hh>
12 #include <vcsn/algos/transpose.hh>
14 #include <vcsn/dyn/automaton.hh>
15 #include <vcsn/dyn/fwd.hh>
16 #include <vcsn/misc/builtins.hh>
19 #include <vcsn/misc/vector.hh> // has
20 
21 namespace vcsn
22 {
23  namespace detail
24  {
25 
26  /*--------------------------------.
27  | strongly connected component. |
28  `--------------------------------*/
29 
37  template <typename Aut>
38  using component_t = std::unordered_set<state_t_of<Aut>>;
39 
41  template <typename Aut>
42  using components_t = std::vector<component_t<Aut>>;
43 
44 
45  /*---------------------.
46  | reverse_postorder. |
47  `---------------------*/
48 
50  template <typename Aut>
52  {
53  public:
55 
56  reverse_postorder_impl(const Aut& aut)
57  : aut_{aut}
58  {
59  rvp_.reserve(aut->num_all_states());
60  for (auto s : aut->states())
61  if (!has(marked_, s))
62  dfs(s);
63  }
64 
65  std::vector<state_t>& reverse_post()
66  {
67  return rvp_;
68  }
69 
70  private:
71  void dfs(state_t s)
72  {
73  marked_.emplace(s);
74  for (auto t : aut_->out(s))
75  {
76  auto dst = aut_->dst_of(t);
77  if (!has(marked_, dst))
78  dfs(dst);
79  }
80  rvp_.emplace_back(s);
81  }
82 
84  Aut aut_;
86  std::vector<state_t> rvp_;
88  std::set<state_t> marked_;
89  };
90  }
91 
93  template <typename Aut>
94  inline
95  std::vector<state_t_of<Aut>>
96  reverse_postorder(const Aut& aut)
97  {
99  return dv.reverse_post();
100  }
101 
102 
103  namespace detail
104  {
105  /*----------------.
106  | scc_dijkstra. |
107  `----------------*/
108 
113  template <typename Aut>
115  {
116  public:
120 
121  scc_dijkstra_impl(const Aut& aut)
122  : aut_{aut}
123  {}
124 
126  {
127  for (auto s : aut_->states())
128  if (!has(component_, s))
129  dfs(s);
130  return components_;
131  }
132 
133  private:
134  void dfs(state_t s)
135  {
136  preorder_[s] = count_;
137  ++count_;
138  unassigned_.push(s);
139  uncertain_.push(s);
140  for (auto t: aut_->out(s))
141  {
142  state_t dst = aut_->dst_of(t);
143  if (!has(preorder_, dst))
144  dfs(dst);
145  else if (!has(component_, dst))
146  {
147  size_t dstpo = preorder_[dst];
148  while (dstpo < preorder_[uncertain_.top()])
149  uncertain_.pop();
150  }
151  }
152  if (s == uncertain_.top())
153  {
154  uncertain_.pop();
155  auto scc_num = components_.size();
156  components_.emplace_back();
157  component_t& scc = components_.back();
158  for (state_t r = unassigned_.top();
159  !unassigned_.empty();
160  unassigned_.pop(), r = unassigned_.top())
161  {
162  component_[r] = scc_num;
163  scc.insert(r);
164  if (r == s)
165  break;
166  }
167  }
168  }
169 
171  Aut aut_;
175  std::stack<state_t> unassigned_;
179  std::stack<state_t> uncertain_;
181  std::size_t count_ = 0;
182 
184  std::unordered_map<state_t, size_t> component_;
185 
186  std::unordered_map<state_t, size_t> preorder_;
189  };
190 
191  /*----------------.
192  | scc_kosaraju. |
193  `----------------*/
194 
197  template <typename Aut>
199  {
200  public:
204 
205  scc_kosaraju_impl(const Aut& aut)
206  : aut_{aut}
207  {
208  auto trans = ::vcsn::transpose(aut);
209  auto todo = ::vcsn::reverse_postorder(trans);
210  while (!todo.empty())
211  {
212  auto s = todo.back();
213  todo.pop_back();
214  if (!has(marked_, s))
215  {
216  dfs(s);
217  ++num_;
218  }
219  }
220  }
221 
222  const components_t& components() const
223  {
224  return components_;
225  }
226 
227  private:
228  void dfs(state_t s)
229  {
230  marked_.emplace(s);
231  if (num_ == components_.size())
232  components_.emplace_back(component_t{s});
233  else
234  components_[num_].emplace(s);
235 
236  for (auto t : aut_->out(s))
237  {
238  auto dst = aut_->dst_of(t);
239  if (!has(marked_, dst))
240  dfs(dst);
241  }
242  }
243 
245  Aut aut_;
247  std::size_t num_ = 0;
250  std::unordered_set<state_t> marked_;
251  };
252 
253 
254  /*--------------------.
255  | tarjan_iterative. |
256  `--------------------*/
257 
263  template <typename Aut>
265  {
266  public:
269 
272 
274  : aut_{aut}
275  {
276  for (auto s : aut_->states())
277  if (!has(number_, s))
278  dfs(s);
279  }
280 
281  const components_t& components() const
282  {
283  return components_;
284  }
285 
286  private:
287  void dfs(state_t s)
288  {
289  number_[s] = low_[s] = curr_state_num_++;
290  dfs_stack_.emplace_back(s, aut_->out(s).begin(), aut_->out(s).end());
291  stack_.push_back(s);
292  while (!dfs_stack_.empty())
293  {
294  auto& st = dfs_stack_.back();
295  auto src = st.state;
296  if (st.pos != st.end)
297  {
298  auto dst = aut_->dst_of(*st.pos);
299  ++st.pos;
300  if (!has(number_, dst))
301  {
302  number_[dst] = low_[dst] = curr_state_num_++;
303  const auto& out = aut_->out(dst);
304  dfs_stack_.emplace_back(dst, out.begin(), out.end());
305  stack_.push_back(dst);
306  }
307  else if (low_[dst] < low_[src])
308  low_[src] = low_[dst];
309  }
310  else
311  {
312  if (low_[src] == number_[src])
313  {
314  components_.emplace_back();
315  auto& com = components_.back();
316  state_t w;
317  do
318  {
319  w = stack_.back();
320  stack_.pop_back();
321  com.emplace(w);
322  low_[w] = low_max_;
323  }
324  while (w != src);
325  }
326  dfs_stack_.pop_back();
327  if (!dfs_stack_.empty())
328  {
329  auto& parent = dfs_stack_.back();
330  if (low_[src] < low_[parent.state])
331  low_[parent.state] = low_[src];
332  }
333  }
334  }
335  }
336 
338  Aut aut_;
339 
341  struct step_t;
342  std::vector<step_t> dfs_stack_;
343 
345  std::size_t curr_state_num_ = 0;
347  std::unordered_map<state_t, std::size_t> number_;
349  std::unordered_map<state_t, std::size_t> low_;
351  std::size_t low_max_ = std::numeric_limits<unsigned int>::max();
352 
354  std::vector<state_t> stack_;
357 
359  using iterator_t = decltype(aut_->out(state_t{}).begin());
360 
363  struct step_t
364  {
366  : state{s}, pos{p}, end{e} {}
370  };
371  };
372 
373 
374  /*--------------------.
375  | tarjan_recursive. |
376  `--------------------*/
377 
383  template <typename Aut>
385  {
386  public:
390 
392  : aut_{aut}
393  {
394  for (auto s : aut_->states())
395  if (!has(marked_, s))
396  dfs(s);
397  }
398 
399  const components_t& components() const
400  {
401  return components_;
402  }
403 
404  private:
405  void dfs(state_t s)
406  {
407  std::size_t min = curr_state_num_++;
408  low_.emplace(s, min);
409  marked_.emplace(s);
410  stack_.push_back(s);
411 
412  for (auto t : aut_->out(s))
413  {
414  auto dst = aut_->dst_of(t);
415  if (!has(marked_, dst))
416  dfs(dst);
417  if (low_[dst] < min)
418  min = low_[dst];
419  }
420  if (min < low_[s])
421  {
422  low_[s] = min;
423  return;
424  }
425 
426  components_.emplace_back();
427  auto& com = components_.back();
428  state_t w;
429  do
430  {
431  w = stack_.back();
432  stack_.pop_back();
433  com.emplace(w);
434  // This state belong only one component
435  // so remove it by update low value to max size.
436  low_[w] = std::numeric_limits<size_t>::max();
437  }
438  while (w != s);
439  }
440 
442  Aut aut_;
445  std::size_t curr_state_num_ = 0;
449  std::unordered_set<state_t> marked_;
452  std::unordered_map<state_t, std::size_t> low_;
454  std::vector<state_t> stack_;
455  };
456  }
457 
458 
459  /*-------.
460  | scc. |
461  `-------*/
462 
463  enum class scc_algo_t
464  {
465  dijkstra,
468  kosaraju
469  };
470 
471  inline scc_algo_t scc_algo(const std::string& algo)
472  {
473  scc_algo_t res;
474  if (algo == "dijkstra")
475  res = scc_algo_t::dijkstra;
476  else if (algo == "auto" || algo == "tarjan_iterative")
478  else if (algo == "tarjan_recursive")
480  else if (algo == "kosaraju")
481  res = scc_algo_t::kosaraju;
482  else
483  raise("scc: invalid algorithm: ", str_escape(algo));
484  return res;
485  }
486 
488  template <typename Aut>
489  inline
490  const detail::components_t<Aut>
491  strong_components(const Aut& aut,
493  {
494  switch (algo)
495  {
504  }
506  }
507 
509  template <typename Aut>
510  inline
512  aut_of_component(const detail::component_t<Aut>& com, const Aut& aut)
513  {
514  auto res = make_fresh_automaton(aut);
515  using res_t = decltype(res);
516  std::unordered_map<state_t_of<Aut>, state_t_of<res_t>> map;
517  auto s0 = *com.begin();
518  map[s0] = res->new_state();
519  res->set_initial(map[s0]);
520  for (auto s : com)
521  {
522  if (!has(map, s))
523  map[s] = res->new_state();
524  for (auto t : aut->out(s))
525  {
526  auto dst = aut->dst_of(t);
527  if (!has(com, dst))
528  continue;
529  if (!has(map, dst))
530  map[dst] = res->new_state();
531  res->new_transition(map[s], map[dst], aut->label_of(t));
532  }
533  }
534  return res;
535  }
536 
537  /*-----------------.
538  | scc_automaton. |
539  `-----------------*/
540 
541  namespace detail
542  {
544  template <typename Aut>
546  : public automaton_decorator<Aut>
547  {
548  public:
549  using automaton_t = Aut;
554 
556  : super_t(input)
557  {
558  // Components are numbered by ordered of discovery. Reverse
559  // this, so that components are roughly numbered as the
560  // condensation state numbers would be (0 as an initial
561  // state).
562  const auto& cs = vcsn::strong_components(aut_, algo);
563  // FIXME: std::rbegin/rend does not work with libstdc++.
564  components_.assign(boost::rbegin(cs), boost::rend(cs));
565  size_t num_sccs = components_.size();
566  for (size_t i = 0; i < num_sccs; ++i)
567  for (auto s : components_[i])
568  component_[s] = i;
569  }
570 
572  static symbol sname()
573  {
574  static symbol res("scc_automaton<"
576  return res;
577  }
578 
579  std::ostream& print_set(std::ostream& o, format fmt = {}) const
580  {
581  o << "scc_automaton<";
582  aut_->print_set(o, fmt);
583  return o << '>';
584  }
585 
586  bool state_has_name(state_t) const
587  {
588  return true;
589  }
590 
591  std::ostream& print_state_name(state_t s, std::ostream& o,
592  format fmt = {},
593  bool = false) const
594  {
595  o << component_.at(s) << '.';
596  aut_->print_state_name(s, o, fmt, true);
597  return o;
598  }
599 
600  const component_t& component(unsigned num) const
601  {
602  require(num < components_.size(),
603  "component: invalid component number: ",
604  num, ": there are ", components_.size(), " components");
605  return components_[num];
606  }
607 
608  const components_t& components() const
609  {
610  return components_;
611  }
612 
613  size_t num_components() const
614  {
615  return components_.size();
616  }
617 
618  private:
619  using super_t::aut_;
621  std::map<state_t, size_t> component_;
622  components_t components_;
623  };
624  }
625 
626  template <typename Aut>
627  using scc_automaton = std::shared_ptr<detail::scc_automaton_impl<Aut>>;
628 
630  template <typename Aut>
631  inline
632  scc_automaton<Aut>
633  scc(const Aut& aut, const std::string& algo = "auto")
634  {
635  return make_shared_ptr<scc_automaton<Aut>>(aut, scc_algo(algo));
636  }
637 
638  namespace dyn
639  {
640  namespace detail
641  {
643  template <typename Aut, typename String>
644  inline
645  automaton scc(const automaton& aut, const std::string& algo)
646  {
647  const auto& a = aut->as<Aut>();
648  return make_automaton(::vcsn::scc(a, algo));
649  }
650  }
651  }
652 
653  /*----------------.
654  | num_components. |
655  `----------------*/
656 
658  template <typename Aut>
659  inline
660  std::size_t num_components(const scc_automaton<Aut>& aut)
661  {
662  return aut->num_components();
663  }
664 
665  template <typename Aut>
666  inline
667  std::size_t num_components(const Aut&)
668  {
669  raise("num_components: requires an scc_automaton");
670  }
671 
672  namespace dyn
673  {
674  namespace detail
675  {
677  template <typename Aut>
678  inline
679  std::size_t num_components(const automaton& aut)
680  {
681  const auto& a = aut->as<Aut>();
682  return ::vcsn::num_components(a);
683  }
684  }
685  }
686 
687 
688  /*-----------.
689  | component. |
690  `-----------*/
691 
695  template <typename Aut>
696  inline
697  filter_automaton<scc_automaton<Aut>>
698  component(const scc_automaton<Aut>& aut, unsigned num)
699  {
700  return vcsn::filter(aut, aut->component(num));
701  }
702 
703  template <typename Aut>
704  inline
705  void
706  component(const Aut&, unsigned)
707  {
708  raise("component: requires an scc_automaton");
709  }
710 
711  namespace dyn
712  {
713  namespace detail
714  {
716  template <typename Aut, typename Unsigned>
717  inline
718  automaton component(const automaton& aut, unsigned num)
719  {
720  const auto& a = aut->as<Aut>();
721  return make_automaton(::vcsn::component(a, num));
722  }
723  }
724  }
725 
726 
727  /*----------.
728  | condense. |
729  `----------*/
730 
733  template <typename Aut>
734  inline
735  partition_automaton<scc_automaton<Aut>>
736  condense(const scc_automaton<Aut>& aut)
737  {
738  auto res = make_shared_ptr<partition_automaton<scc_automaton<Aut>>>(aut);
739  using state_t = state_t_of<Aut>;
741  std::unordered_map<state_t, state_t> map;
742 
743  // Add states to new automaton.
744  std::set<state_t> ss;
745  for (const auto& com : aut->components())
746  {
747  ss.clear();
748  ss.insert(begin(com), end(com));
749  state_t new_state = res->new_state(ss);
750  for (auto s : com)
751  map[s] = new_state;
752  }
753  map[aut->pre()] = res->pre();
754  map[aut->post()] = res->post();
755 
756  // Add transitions to new automaton.
757  for (auto t: aut->all_transitions())
758  {
759  auto s = map[aut->src_of(t)];
760  auto d = map[aut->dst_of(t)];
761  if (s != d)
762  res->add_transition(s, d, aut->label_of(t), aut->weight_of(t));
763  }
764  return res;
765  }
766 
767  template <typename Aut>
768  inline
769  partition_automaton<Aut>
770  condense(const Aut&)
771  {
772  raise("condense: requires an scc_automaton");
773  }
774 
775  namespace dyn
776  {
777  namespace detail
778  {
780  template <typename Aut>
781  inline
782  automaton condense(const automaton& aut)
783  {
784  const auto& a = aut->as<Aut>();
785  return make_automaton(::vcsn::condense(a));
786  }
787  }
788  }
789 }
scc_tarjan_recursive_impl(const Aut &aut)
Definition: scc.hh:391
scc_kosaraju_impl(const Aut &aut)
Definition: scc.hh:205
state_t_of< Aut > state_t
Definition: scc.hh:551
std::set< state_t > marked_
Store the visited states.
Definition: scc.hh:88
std::ostream & str_escape(std::ostream &os, const std::string &str)
Output a string, escaping special characters.
Definition: escape.cc:43
std::vector< state_t > rvp_
Revert postorder of dfs.
Definition: scc.hh:86
void dfs(state_t s)
Definition: scc.hh:228
state_t_of< Aut > state_t
Definition: scc.hh:201
scc_tarjan_iterative_impl(const Aut &aut)
Definition: scc.hh:273
void dfs(state_t s)
Definition: scc.hh:134
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
std::unordered_set< state_t > marked_
Definition: scc.hh:250
std::ostream & print_set(std::ostream &o, format fmt={}) const
Definition: scc.hh:579
AutOut make_fresh_automaton(const AutIn &model)
Create an empty, mutable, automaton, based on another one.
Definition: copy.hh:239
Compute the strongly connected components using Dijkstra's algorithm.
Definition: scc.hh:114
scc_dijkstra_impl(const Aut &aut)
Definition: scc.hh:121
Aut aut_
Input automaton.
Definition: scc.hh:245
std::unordered_map< state_t, std::size_t > low_
low_[s] is minimum of state that it can go.
Definition: scc.hh:349
typename detail::state_t_of_impl< base_t< ValueSet >>::type state_t_of
Definition: traits.hh:48
std::unordered_map< state_t, std::size_t > number_
Store the visit order of each state.
Definition: scc.hh:347
components_t components_
All components.
Definition: scc.hh:356
const detail::components_t< Aut > strong_components(const Aut &aut, scc_algo_t algo=scc_algo_t::tarjan_iterative)
Find all strongly connected components of aut.
Definition: scc.hh:491
detail::components_t< Aut > components_t
Definition: scc.hh:389
std::vector< component_t< Aut >> components_t
A set of strongly-connected components.
Definition: scc.hh:42
std::size_t low_max_
the maximum possible of a value in low_.
Definition: scc.hh:351
detail::component_t< Aut > component_t
Definition: scc.hh:388
Aggregate an automaton, and forward calls to it.
detail::components_t< Aut > components_t
Definition: scc.hh:203
std::size_t curr_state_num_
The current visited state.
Definition: scc.hh:345
const components_t & components() const
Definition: scc.hh:222
std::unordered_map< state_t, std::size_t > low_
low_[s] is minimum of low_{X}, with X is all states on output transitions of s.
Definition: scc.hh:452
transition_t_of< Aut > transition_t
Definition: scc.hh:268
Aut aut_
Input automaton.
Definition: scc.hh:442
Aut aut_
Input automaton.
Definition: scc.hh:338
Aut transpose(const transpose_automaton< Aut > &aut)
Definition: transpose.hh:235
scc_algo_t
Definition: scc.hh:463
Tarjan's algorithm to find all strongly connected components: recursive implementation.
Definition: scc.hh:384
detail::component_t< Aut > component_t
Definition: scc.hh:118
scc_automaton< Aut > scc(const Aut &aut, const std::string &algo="auto")
Get scc_automaton from aut.
Definition: scc.hh:633
An input/output format.
Definition: format.hh:11
std::stack< state_t > uncertain_
Stack P contains vertices that have not yet been determined to belong to different strongly connected...
Definition: scc.hh:179
std::unordered_set< state_t > marked_
Visited states.
Definition: scc.hh:449
scc_algo_t scc_algo(const std::string &algo)
Definition: scc.hh:471
fresh_automaton_t_of< Aut > aut_of_component(const detail::component_t< Aut > &com, const Aut &aut)
Generate a subautomaton corresponding to an SCC.
Definition: scc.hh:512
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
std::vector< state_t > stack_
List of states in the same the component.
Definition: scc.hh:354
An automaton decorator that maps states to their scc-number.
Definition: scc.hh:545
std::stack< state_t > unassigned_
Stack S contains all the vertices that have not yet been assigned to a strongly connected component...
Definition: scc.hh:175
Get all states in reverse postorder using depth first search.
Definition: scc.hh:51
const components_t & components() const
Definition: scc.hh:399
std::vector< state_t_of< Aut > > reverse_postorder(const Aut &aut)
Get all states in reverse postorder.
Definition: scc.hh:96
detail::components_t< Aut > components_t
Definition: scc.hh:271
std::vector< state_t > & reverse_post()
Definition: scc.hh:65
detail::component_t< Aut > component_t
Definition: scc.hh:270
Tarjan's algorithm to find all strongly connected components: iterative implementation.
Definition: scc.hh:264
typename detail::transition_t_of_impl< base_t< ValueSet >>::type transition_t_of
Definition: traits.hh:49
reverse_postorder_impl(const Aut &aut)
Definition: scc.hh:56
symbol sname()
Definition: name.hh:67
std::unordered_set< state_t_of< Aut >> component_t
A strongly-connected component: set of states.
Definition: scc.hh:38
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:23
std::unordered_map< state_t, size_t > component_
For each state, its component number.
Definition: scc.hh:184
components_t components_
All components.
Definition: scc.hh:249
Aut aut_
Input automaton.
Definition: scc.hh:84
detail::component_t< Aut > component_t
Definition: scc.hh:553
std::unordered_map< state_t, size_t > preorder_
Definition: scc.hh:186
detail::components_t< Aut > components_t
Definition: scc.hh:552
decltype(aut_->out(state_t{}).begin()) iterator_t
Iterator on outgoing transitions.
Definition: scc.hh:359
std::map< state_t, size_t > component_
For each state, its component number.
Definition: scc.hh:621
ATTRIBUTE_PURE bool has(const std::deque< T, Allocator > &s, const T &e)
Whether e is member of s.
Definition: deque.hh:13
Step of one state contain infomation next successor and end iterator(output transitions or successors...
Definition: scc.hh:363
std::size_t num_
The current component number.
Definition: scc.hh:247
std::size_t count_
Current state number (not it's id, but its count).
Definition: scc.hh:181
static symbol sname()
Static name.
Definition: scc.hh:572
Aut aut_
Input automaton.
Definition: scc.hh:171
detail::components_t< Aut > components_t
Definition: scc.hh:119
const components_t & components() const
Definition: scc.hh:281
state_t_of< Aut > state_t
Definition: scc.hh:54
scc_automaton_impl(const automaton_t &input, scc_algo_t algo)
Definition: scc.hh:555
components_t components_
All the components.
Definition: scc.hh:188
#define BUILTIN_UNREACHABLE()
Definition: builtins.hh:13
std::vector< step_t > dfs_stack_
Definition: scc.hh:341
step_t(state_t s, iterator_t p, iterator_t e)
Definition: scc.hh:365
state_t_of< Aut > state_t
Definition: scc.hh:117
std::vector< state_t > stack_
List of states in the same the component.
Definition: scc.hh:454
const components_t & components()
Definition: scc.hh:125
components_t components_
All components.
Definition: scc.hh:447
detail::component_t< Aut > component_t
Definition: scc.hh:202
Compute the strongly connected components using Kosaraju's algorithm.
Definition: scc.hh:198