Vcsn  2.8
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/tags.hh>
13 #include <vcsn/algos/transpose.hh>
15 #include <vcsn/dyn/automaton.hh>
16 #include <vcsn/dyn/fwd.hh>
17 #include <vcsn/misc/builtins.hh>
18 #include <vcsn/misc/getargs.hh>
21 #include <vcsn/misc/vector.hh> // has
22 
23 namespace vcsn
24 {
25  namespace detail
26  {
27 
28  /*--------------------------------.
29  | strongly connected component. |
30  `--------------------------------*/
31 
40  template <Automaton Aut>
41  using component_t = std::unordered_set<state_t_of<Aut>>;
42 
44  template <Automaton Aut>
45  using components_t = std::vector<component_t<Aut>>;
46 
47 
48  /*---------------------.
49  | reverse_postorder. |
50  `---------------------*/
51 
53  template <Automaton Aut>
55  {
56  public:
58 
59  reverse_postorder_impl(const Aut& aut)
60  : aut_{aut}
61  {
62  // FIXME: wrong! Should be states_size. Or better yet: a
63  // dedicated state-map type.
64  rvp_.reserve(aut->num_all_states());
65  for (auto s : aut->states())
66  if (!has(marked_, s))
67  dfs(s);
68  }
69 
70  // FIXME: Wrong. Should be const, or by value, and use
71  // std::move.
72  std::vector<state_t>& reverse_post()
73  {
74  return rvp_;
75  }
76 
77  private:
78  void dfs(state_t s)
79  {
80  marked_.emplace(s);
81  for (auto t : out(aut_, s))
82  {
83  auto dst = aut_->dst_of(t);
84  if (!has(marked_, dst))
85  dfs(dst);
86  }
87  rvp_.emplace_back(s);
88  }
89 
91  Aut aut_;
93  std::vector<state_t> rvp_;
95  std::unordered_set<state_t> marked_;
96  };
97  }
98 
100  template <Automaton Aut>
101  std::vector<state_t_of<Aut>>
102  reverse_postorder(const Aut& aut)
103  {
105  return dv.reverse_post();
106  }
107 
108 
109  namespace detail
110  {
115  template <Automaton Aut, typename Tag = auto_tag>
116  class scc_impl;
117 
118  /*------------.
119  | dijkstra. |
120  `------------*/
121 
126  template <Automaton Aut>
127  class scc_impl<Aut, dijkstra_tag>
128  {
129  public:
133 
134  scc_impl(const Aut& aut)
135  : aut_{aut}
136  {}
137 
139  {
140  for (auto s : aut_->states())
141  if (!has(component_, s))
142  dfs(s);
143  return components_;
144  }
145 
146  private:
147  void dfs(state_t s)
148  {
149  preorder_[s] = count_;
150  ++count_;
151  unassigned_.push(s);
152  uncertain_.push(s);
153  for (auto t: out(aut_, s))
154  {
155  state_t dst = aut_->dst_of(t);
156  if (!has(preorder_, dst))
157  dfs(dst);
158  else if (!has(component_, dst))
159  {
160  size_t dstpo = preorder_[dst];
161  while (dstpo < preorder_[uncertain_.top()])
162  uncertain_.pop();
163  }
164  }
165  if (s == uncertain_.top())
166  {
167  uncertain_.pop();
168  auto scc_num = components_.size();
169  components_.emplace_back();
170  component_t& scc = components_.back();
171  for (state_t r = unassigned_.top();
172  !unassigned_.empty();
173  unassigned_.pop(), r = unassigned_.top())
174  {
175  component_[r] = scc_num;
176  scc.insert(r);
177  if (r == s)
178  break;
179  }
180  }
181  }
182 
184  Aut aut_;
188  std::stack<state_t> unassigned_;
192  std::stack<state_t> uncertain_;
194  std::size_t count_ = 0;
195 
197  std::unordered_map<state_t, size_t> component_;
198 
199  std::unordered_map<state_t, size_t> preorder_;
202  };
203  }
204 
205  /*------------.
206  | kosaraju. |
207  `------------*/
208 
210  struct kosaraju_tag {};
211 
212  namespace detail
213  {
216  template <Automaton Aut>
217  class scc_impl<Aut, kosaraju_tag>
218  {
219  public:
223 
224  scc_impl(const Aut& aut)
225  : aut_{aut}
226  {
227  auto trans = ::vcsn::transpose(aut);
228  auto todo = ::vcsn::reverse_postorder(trans);
229  while (!todo.empty())
230  {
231  auto s = todo.back();
232  todo.pop_back();
233  if (!has(marked_, s))
234  {
235  dfs(s);
236  ++num_;
237  }
238  }
239  }
240 
241  const components_t& components() const
242  {
243  return components_;
244  }
245 
246  private:
247  void dfs(state_t s)
248  {
249  marked_.emplace(s);
250  if (num_ == components_.size())
251  components_.emplace_back(component_t{s});
252  else
253  components_[num_].emplace(s);
254 
255  for (auto t : out(aut_, s))
256  {
257  auto dst = aut_->dst_of(t);
258  if (!has(marked_, dst))
259  dfs(dst);
260  }
261  }
262 
264  Aut aut_;
266  std::size_t num_ = 0;
269  std::unordered_set<state_t> marked_;
270  };
271  }
272 
273  /*---------------------.
274  | tarjan, iterative. |
275  `---------------------*/
276 
280 
281  namespace detail
282  {
288  template <Automaton Aut>
290  {
291  public:
294 
297 
298  scc_impl(const Aut& aut)
299  : aut_{aut}
300  {
301  for (auto s : aut_->states())
302  if (!has(number_, s))
303  dfs(s);
304  }
305 
306  const components_t& components() const
307  {
308  return components_;
309  }
310 
311  private:
312  void dfs(state_t s)
313  {
314  number_[s] = low_[s] = curr_state_num_++;
315  dfs_stack_.emplace_back(s, out(aut_, s).begin(), out(aut_, s).end());
316  stack_.push_back(s);
317  while (!dfs_stack_.empty())
318  {
319  auto& st = dfs_stack_.back();
320  auto src = st.state;
321  if (st.pos != st.end)
322  {
323  auto dst = aut_->dst_of(*st.pos);
324  ++st.pos;
325  if (!has(number_, dst))
326  {
327  number_[dst] = low_[dst] = curr_state_num_++;
328  const auto& ts = out(aut_, dst);
329  dfs_stack_.emplace_back(dst, ts.begin(), ts.end());
330  stack_.push_back(dst);
331  }
332  else if (low_[dst] < low_[src])
333  low_[src] = low_[dst];
334  }
335  else
336  {
337  if (low_[src] == number_[src])
338  {
339  components_.emplace_back();
340  auto& com = components_.back();
341  state_t w;
342  do
343  {
344  w = stack_.back();
345  stack_.pop_back();
346  com.emplace(w);
347  low_[w] = low_max_;
348  }
349  while (w != src);
350  }
351  dfs_stack_.pop_back();
352  if (!dfs_stack_.empty())
353  {
354  auto& parent = dfs_stack_.back();
355  if (low_[src] < low_[parent.state])
356  low_[parent.state] = low_[src];
357  }
358  }
359  }
360  }
361 
363  Aut aut_;
364 
366  struct step_t;
367  std::vector<step_t> dfs_stack_;
368 
370  std::size_t curr_state_num_ = 0;
372  std::unordered_map<state_t, std::size_t> number_;
374  std::unordered_map<state_t, std::size_t> low_;
376  std::size_t low_max_ = std::numeric_limits<unsigned int>::max();
377 
379  std::vector<state_t> stack_;
382 
384  using iterator_t = decltype(out(aut_, state_t{}).begin());
385 
388  struct step_t
389  {
391  : state{s}, pos{p}, end{e} {}
395  };
396  };
397  }
398 
399  /*--------------------.
400  | tarjan_recursive. |
401  `--------------------*/
402 
406 
407  namespace detail
408  {
414  template <Automaton Aut>
416  {
417  public:
421 
422  scc_impl(const Aut& aut)
423  : aut_{aut}
424  {
425  for (auto s : aut_->states())
426  if (!has(marked_, s))
427  dfs(s);
428  }
429 
430  const components_t& components() const
431  {
432  return components_;
433  }
434 
435  private:
436  void dfs(state_t s)
437  {
438  std::size_t min = curr_state_num_++;
439  low_.emplace(s, min);
440  marked_.emplace(s);
441  stack_.push_back(s);
442 
443  for (auto t : out(aut_, s))
444  {
445  auto dst = aut_->dst_of(t);
446  if (!has(marked_, dst))
447  dfs(dst);
448  if (low_[dst] < min)
449  min = low_[dst];
450  }
451  if (min < low_[s])
452  {
453  low_[s] = min;
454  return;
455  }
456 
457  components_.emplace_back();
458  auto& com = components_.back();
459  state_t w;
460  do
461  {
462  w = stack_.back();
463  stack_.pop_back();
464  com.emplace(w);
465  // This state belong only one component
466  // so remove it by update low value to max size.
467  low_[w] = std::numeric_limits<size_t>::max();
468  }
469  while (w != s);
470  }
471 
473  Aut aut_;
476  std::size_t curr_state_num_ = 0;
480  std::unordered_set<state_t> marked_;
483  std::unordered_map<state_t, std::size_t> low_;
485  std::vector<state_t> stack_;
486  };
487  }
488 
489  /*--------.
490  | auto. |
491  `--------*/
492 
493  namespace detail
494  {
496  template <Automaton Aut>
497  class scc_impl<Aut, auto_tag>
498  : public scc_impl<Aut, tarjan_iterative_tag>
499  {
501  using super_t::super_t;
502  };
503  }
504 
505 
506  /*-------.
507  | scc. |
508  `-------*/
509 
510  enum class scc_algo_t
511  {
512  auto_,
513  dijkstra,
516  kosaraju
517  };
518 
519  inline scc_algo_t scc_algo(const std::string& algo)
520  {
521  static const auto map = getarg<scc_algo_t>
522  {
523  "strongly connected components algorithm",
524  {
525  {"auto", scc_algo_t::auto_},
526  {"dijkstra", scc_algo_t::dijkstra},
527  {"kosaraju", scc_algo_t::kosaraju},
528  {"tarjan", "tarjan,iterative"},
529  {"tarjan,iterative", scc_algo_t::tarjan_iterative},
530  {"tarjan,recursive", scc_algo_t::tarjan_recursive},
531  {"tarjan_iterative", "tarjan,iterative"},
532  {"tarjan_recursive", "tarjan,recursive"},
533  }
534  };
535  return map[algo];
536  }
537 
542  template <Automaton Aut, typename Tag = auto_tag>
544  strong_components(const Aut& aut, Tag = {})
545  {
546  return detail::scc_impl<Aut, Tag>{aut}.components();
547  }
548 
553  template <Automaton Aut>
555  strong_components(const Aut& aut,
557  {
558  switch (algo)
559  {
560  case scc_algo_t::auto_:
561  return strong_components(aut, auto_tag{});
563  return strong_components(aut, dijkstra_tag{});
565  return strong_components(aut, kosaraju_tag{});
570  }
572  }
573 
575  template <Automaton Aut>
577  aut_of_component(const detail::component_t<Aut>& com, const Aut& aut)
578  {
579  auto res = make_fresh_automaton(aut);
580  using res_t = decltype(res);
581  auto map = std::unordered_map<state_t_of<Aut>, state_t_of<res_t>>{};
582  auto s0 = *com.begin();
583  map[s0] = res->new_state();
584  res->set_initial(map[s0]);
585  for (auto s : com)
586  {
587  if (!has(map, s))
588  map[s] = res->new_state();
589  for (auto t : out(aut, s))
590  {
591  auto dst = aut->dst_of(t);
592  if (!has(com, dst))
593  continue;
594  if (!has(map, dst))
595  map[dst] = res->new_state();
596  res->new_transition(map[s], map[dst], aut->label_of(t));
597  }
598  }
599  return res;
600  }
601 
602  /*-----------------.
603  | scc_automaton. |
604  `-----------------*/
605 
606  namespace detail
607  {
609  template <Automaton Aut>
611  : public automaton_decorator<Aut>
612  {
613  public:
614  using automaton_t = Aut;
619 
621  : super_t(input)
622  {
623  // Components are numbered by ordered of discovery. Reverse
624  // this, so that components are roughly numbered as the
625  // condensation state numbers would be (0 as an initial
626  // state).
627  const auto& cs = vcsn::strong_components(aut_, algo);
628  // FIXME: std::rbegin/rend does not work with libstdc++.
629  components_.assign(boost::rbegin(cs), boost::rend(cs));
630  size_t num_sccs = components_.size();
631  for (size_t i = 0; i < num_sccs; ++i)
632  for (auto s : components_[i])
633  component_[s] = i;
634  }
635 
637  static symbol sname()
638  {
639  static auto res = symbol{"scc_automaton<"
641  return res;
642  }
643 
644  std::ostream& print_set(std::ostream& o, format fmt = {}) const
645  {
646  o << "scc_automaton<";
647  aut_->print_set(o, fmt);
648  return o << '>';
649  }
650 
651  bool state_has_name(state_t) const
652  {
653  return true;
654  }
655 
656  std::ostream& print_state_name(state_t s, std::ostream& o,
657  format fmt = {},
658  bool = false) const
659  {
660  o << component_.at(s) << '.';
661  aut_->print_state_name(s, o, fmt, true);
662  return o;
663  }
664 
665  const component_t& component(unsigned num) const
666  {
667  VCSN_REQUIRE(num < components_.size(),
668  "component: invalid component number: ",
669  num, ": there are ", components_.size(), " components");
670  return components_[num];
671  }
672 
673  const components_t& components() const
674  {
675  return components_;
676  }
677 
678  size_t num_components() const
679  {
680  return components_.size();
681  }
682 
683  private:
684  using super_t::aut_;
686  std::map<state_t, size_t> component_;
687  components_t components_;
688  };
689  }
690 
691  template <Automaton Aut>
692  using scc_automaton = std::shared_ptr<detail::scc_automaton_impl<Aut>>;
693 
695  template <Automaton Aut>
696  scc_automaton<Aut>
697  scc(const Aut& aut, const std::string& algo = "auto")
698  {
699  return make_shared_ptr<scc_automaton<Aut>>(aut, scc_algo(algo));
700  }
701 
702  namespace dyn
703  {
704  namespace detail
705  {
707  template <Automaton Aut, typename String>
708  automaton scc(const automaton& aut, const std::string& algo)
709  {
710  const auto& a = aut->as<Aut>();
711  return ::vcsn::scc(a, algo);
712  }
713  }
714  }
715 
716  /*----------------.
717  | num_components. |
718  `----------------*/
719 
721  template <Automaton Aut>
722  std::size_t num_components(const scc_automaton<Aut>& aut)
723  {
724  return aut->num_components();
725  }
726 
727  template <Automaton Aut>
728  std::size_t num_components(const Aut&)
729  {
730  raise("num_components: requires an scc_automaton");
731  }
732 
733  namespace dyn
734  {
735  namespace detail
736  {
738  template <Automaton Aut>
739  std::size_t num_components(const automaton& aut)
740  {
741  const auto& a = aut->as<Aut>();
742  return ::vcsn::num_components(a);
743  }
744  }
745  }
746 
747 
748  /*-----------.
749  | component. |
750  `-----------*/
751 
755  template <Automaton Aut>
756  filter_automaton<scc_automaton<Aut>>
757  component(const scc_automaton<Aut>& aut, unsigned num)
758  {
759  return vcsn::filter(aut, aut->component(num));
760  }
761 
762  template <Automaton Aut>
763  void
764  component(const Aut&, unsigned)
765  {
766  raise("component: requires an scc_automaton");
767  }
768 
769  namespace dyn
770  {
771  namespace detail
772  {
774  template <Automaton Aut, typename Unsigned>
775  automaton component(const automaton& aut, unsigned num)
776  {
777  const auto& a = aut->as<Aut>();
778  return ::vcsn::component(a, num);
779  }
780  }
781  }
782 
783 
784  /*----------.
785  | condense. |
786  `----------*/
787 
790  template <Automaton Aut>
791  partition_automaton<scc_automaton<Aut>>
792  condense(const scc_automaton<Aut>& aut)
793  {
794  auto res = make_shared_ptr<partition_automaton<scc_automaton<Aut>>>(aut);
795  using state_t = state_t_of<Aut>;
796 
797  // State of aut -> state(component) of new automaton.
798  auto map = std::unordered_map<state_t, state_t>
799  {
800  {aut->pre(), res->pre()},
801  {aut->post(), res->post()},
802  };
803 
804  // Add states to new automaton.
805  for (const auto& com : aut->components())
806  {
807  state_t new_state = res->new_state(com);
808  for (auto s : com)
809  map[s] = new_state;
810  }
811 
812  // Add transitions to new automaton.
813  for (auto t: all_transitions(aut))
814  {
815  auto s = map[aut->src_of(t)];
816  auto d = map[aut->dst_of(t)];
817  if (s != d)
818  res->add_transition(s, d, aut->label_of(t), aut->weight_of(t));
819  }
820  return res;
821  }
822 
823  template <Automaton Aut>
824  partition_automaton<Aut>
825  condense(const Aut&)
826  {
827  raise("condense: requires an scc_automaton");
828  }
829 
830  namespace dyn
831  {
832  namespace detail
833  {
835  template <Automaton Aut>
836  automaton condense(const automaton& aut)
837  {
838  const auto& a = aut->as<Aut>();
839  return ::vcsn::condense(a);
840  }
841  }
842  }
843 }
Aut transpose(const transpose_automaton< Aut > &aut)
The transpose of a transpose automaton is the original automaton.
Definition: transpose.hh:253
detail::components_t< Aut > components_t
Definition: scc.hh:296
ATTRIBUTE_PURE bool has(const boost::container::flat_set< Key, Compare, Allocator > &s, const Key &e)
Whether e is member of s.
Definition: setalpha.hh:26
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
std::vector< state_t > stack_
List of states in the same the component.
Definition: scc.hh:379
std::unordered_set< state_t > marked_
Store the visited states.
Definition: scc.hh:95
std::ostream & print_set(std::ostream &o, format fmt={}) const
Definition: scc.hh:644
detail::component_t< Aut > component_t
Definition: scc.hh:419
std::vector< state_t_of< Aut > > reverse_postorder(const Aut &aut)
Get all states in reverse postorder.
Definition: scc.hh:102
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
detail::component_t< Aut > component_t
Definition: scc.hh:131
return exp min
Definition: multiply.hh:362
const components_t & components() const
Definition: scc.hh:241
Class template for strongly-connected-components computations.
Definition: scc.hh:116
const detail::components_t< Aut > strong_components(const Aut &aut, Tag={})
Find all strongly connected components of aut.
Definition: scc.hh:544
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:577
std::vector< component_t< Aut > > components_t
A set of strongly-connected components.
Definition: scc.hh:45
std::stack< state_t > uncertain_
Stack P contains vertices that have not yet been determined to belong to different strongly connected...
Definition: scc.hh:192
std::unordered_map< state_t, std::size_t > low_
low_[s] is minimum of state that it can go.
Definition: scc.hh:374
std::unordered_set< state_t > marked_
Definition: scc.hh:269
Tarjan&#39;s algorithm to find all strongly connected components: iterative implementation.
Definition: scc.hh:289
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:21
scc_algo_t scc_algo(const std::string &algo)
Definition: scc.hh:519
static symbol sname()
Static name.
Definition: scc.hh:637
scc_automaton_impl(const automaton_t &input, scc_algo_t algo)
Definition: scc.hh:620
components_t components_
All components.
Definition: scc.hh:268
std::unordered_set< state_t_of< Aut > > component_t
A strongly-connected component: set of states.
Definition: scc.hh:41
An automaton decorator that maps states to their scc-number.
Definition: scc.hh:610
An input/output format for valuesets.
Definition: format.hh:13
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
std::vector< state_t > & reverse_post()
Definition: scc.hh:72
components_t components_
All components.
Definition: scc.hh:381
std::unordered_map< state_t, size_t > preorder_
Definition: scc.hh:199
Request the Kosaraju&#39;s algorithm to compute the SCCs.
Definition: scc.hh:210
std::unordered_set< state_t > marked_
Visited states.
Definition: scc.hh:480
Tag to request the most appropriate version of an algorithm.
Definition: tags.hh:16
detail::components_t< Aut > components_t
Definition: scc.hh:222
Get all states in reverse postorder using depth first search.
Definition: scc.hh:54
std::vector< state_t > rvp_
Revert postorder of dfs.
Definition: scc.hh:93
Definition: a-star.hh:8
scc_automaton< Aut > scc(const Aut &aut, const std::string &algo="auto")
Get scc_automaton from aut.
Definition: scc.hh:697
Request the Tarjan&#39;s algorithm to compute the SCCs, implemented with recursion.
Definition: scc.hh:405
detail::component_t< Aut > component_t
Definition: scc.hh:295
Dijkstra implementation.
Definition: tags.hh:144
Request the Tarjan&#39;s algorithm to compute the SCCs, implemented with explicit stack handling...
Definition: scc.hh:279
detail::component_t< Aut > component_t
Definition: scc.hh:221
detail::components_t< Aut > components_t
Definition: scc.hh:420
AutOut make_fresh_automaton(const AutIn &model)
Create an empty, mutable, automaton, based on another one.
Definition: copy.hh:91
Aggregate an automaton, and forward calls to it.
std::unordered_map< state_t, size_t > component_
For each state, its component number.
Definition: scc.hh:197
components_t components_
All the components.
Definition: scc.hh:201
Aut aut_
Input automaton.
Definition: scc.hh:91
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:188
detail::component_t< Aut > component_t
Definition: scc.hh:618
symbol sname()
Definition: name.hh:65
scc_algo_t
Definition: scc.hh:510
A mapping from strings to Values.
Definition: getargs.hh:33
components_t components_
All components.
Definition: scc.hh:478
detail::components_t< Aut > components_t
Definition: scc.hh:617
state_t_of< Aut > state_t
Definition: scc.hh:57
const components_t & components()
Definition: scc.hh:138
decltype(out(aut_, state_t{}).begin()) iterator_t
Iterator on outgoing transitions.
Definition: scc.hh:384
const components_t & components() const
Definition: scc.hh:430
step_t(state_t s, iterator_t p, iterator_t e)
Definition: scc.hh:390
const components_t & components() const
Definition: scc.hh:306
detail::components_t< Aut > components_t
Definition: scc.hh:132
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:483
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
state_t_of< Aut > state_t
Definition: scc.hh:616
reverse_postorder_impl(const Aut &aut)
Definition: scc.hh:59
#define BUILTIN_UNREACHABLE()
Definition: builtins.hh:13
auto map(const std::tuple< Ts... > &ts, Fun f) -> decltype(map_tuple_(f, ts, make_index_sequence< sizeof...(Ts)>()))
Map a function on a tuple, return tuple of the results.
Definition: tuple.hh:223
std::unordered_map< state_t, std::size_t > number_
Store the visit order of each state.
Definition: scc.hh:372
return res
Definition: multiply.hh:399
std::vector< state_t > stack_
List of states in the same the component.
Definition: scc.hh:485
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:86