7 #include <boost/range/rbegin.hpp>
8 #include <boost/range/rend.hpp>
16 #include <vcsn/dyn/fwd.hh>
40 template <Automaton Aut>
44 template <Automaton Aut>
53 template <Automaton Aut>
62 rvp_.reserve(aut->num_all_states());
63 for (
auto s : aut->states())
79 auto dst =
aut_->dst_of(t);
96 template <Automaton Aut>
97 std::vector<state_t_of<Aut>>
111 template <Automaton Aut,
typename Tag = auto_tag>
122 template <Automaton Aut>
136 for (
auto s : aut_->states())
137 if (!
has(component_, s))
145 preorder_[s] = count_;
149 for (
auto t:
out(aut_, s))
152 if (!
has(preorder_, dst))
154 else if (!
has(component_, dst))
156 size_t dstpo = preorder_[dst];
157 while (dstpo < preorder_[uncertain_.top()])
161 if (s == uncertain_.top())
164 auto scc_num = components_.size();
165 components_.emplace_back();
168 !unassigned_.empty();
169 unassigned_.pop(),
r = unassigned_.top())
171 component_[
r] = scc_num;
190 std::size_t count_ = 0;
212 template <Automaton Aut>
225 while (!todo.empty())
227 auto s = todo.back();
229 if (!
has(marked_, s))
246 if (num_ == components_.size())
249 components_[num_].emplace(s);
251 for (
auto t :
out(aut_, s))
253 auto dst = aut_->dst_of(t);
254 if (!
has(marked_, dst))
262 std::size_t num_ = 0;
284 template <Automaton Aut>
297 for (
auto s : aut_->states())
298 if (!
has(number_, s))
310 number_[s] = low_[s] = curr_state_num_++;
311 dfs_stack_.emplace_back(s,
out(aut_, s).begin(),
out(aut_, s).end());
313 while (!dfs_stack_.empty())
315 auto& st = dfs_stack_.back();
317 if (st.pos != st.end)
319 auto dst = aut_->dst_of(*st.pos);
321 if (!
has(number_, dst))
323 number_[dst] = low_[dst] = curr_state_num_++;
324 const auto& ts =
out(aut_, dst);
325 dfs_stack_.emplace_back(dst, ts.begin(), ts.end());
326 stack_.push_back(dst);
328 else if (low_[dst] < low_[src])
329 low_[src] = low_[dst];
333 if (low_[src] == number_[src])
335 components_.emplace_back();
336 auto& com = components_.back();
347 dfs_stack_.pop_back();
348 if (!dfs_stack_.empty())
350 auto& parent = dfs_stack_.back();
351 if (low_[src] < low_[parent.state])
352 low_[parent.state] = low_[src];
366 std::size_t curr_state_num_ = 0;
368 std::unordered_map<state_t, std::size_t>
number_;
370 std::unordered_map<state_t, std::size_t>
low_;
372 std::size_t low_max_ = std::numeric_limits<unsigned int>::max();
387 : state{s}, pos{p}, end{e} {}
410 template <Automaton Aut>
421 for (
auto s : aut_->states())
422 if (!
has(marked_, s))
434 std::size_t
min = curr_state_num_++;
435 low_.emplace(s, min);
439 for (
auto t :
out(aut_, s))
441 auto dst = aut_->dst_of(t);
442 if (!
has(marked_, dst))
453 components_.emplace_back();
454 auto& com = components_.back();
463 low_[w] = std::numeric_limits<size_t>::max();
472 std::size_t curr_state_num_ = 0;
479 std::unordered_map<state_t, std::size_t>
low_;
492 template <Automaton Aut>
494 :
public scc_impl<Aut, tarjan_iterative_tag>
497 using super_t::super_t;
519 "strongly connected components algorithm",
524 {
"tarjan",
"tarjan,iterative"},
527 {
"tarjan_iterative",
"tarjan,iterative"},
528 {
"tarjan_recursive",
"tarjan,recursive"},
538 template <Automaton Aut,
typename Tag = auto_tag>
539 const detail::components_t<Aut>
542 return detail::scc_impl<Aut, Tag>{aut}.components();
549 template <Automaton Aut>
550 const detail::components_t<Aut>
571 template <Automaton Aut>
572 fresh_automaton_t_of<Aut>
576 using res_t = decltype(
res);
578 auto s0 = *com.begin();
579 map[s0] =
res->new_state();
580 res->set_initial(map[s0]);
584 map[s] =
res->new_state();
585 for (
auto t :
out(aut, s))
587 auto dst = aut->dst_of(t);
591 map[dst] =
res->new_state();
592 res->new_transition(map[s], map[dst], aut->label_of(t));
605 template <Automaton Aut>
625 components_.assign(boost::rbegin(cs), boost::rend(cs));
626 size_t num_sccs = components_.size();
627 for (
size_t i = 0; i < num_sccs; ++i)
628 for (
auto s : components_[i])
635 static auto res =
symbol{
"scc_automaton<"
642 o <<
"scc_automaton<";
643 aut_->print_set(o, fmt);
647 bool state_has_name(state_t) const
652 std::ostream& print_state_name(state_t s, std::ostream& o,
656 o << component_.at(s) << '.
';
657 aut_->print_state_name(s, o, fmt, true);
661 const component_t& component(unsigned num) const
663 VCSN_REQUIRE(num < components_.size(),
664 "component: invalid component number: ",
665 num, ": there are ", components_.size(), " components");
666 return components_[num];
669 const components_t& components() const
674 size_t num_components() const
676 return components_.size();
682 std::map<state_t, size_t> component_;
683 components_t components_;
687 template <Automaton Aut>
688 using scc_automaton = std::shared_ptr<detail::scc_automaton_impl<Aut>>;
691 template <Automaton Aut>
693 scc(const Aut& aut, const std::string& algo = "auto")
695 return make_shared_ptr<scc_automaton<Aut>>(aut, scc_algo(algo));
703 template <Automaton Aut, typename String>
704 automaton scc(const automaton& aut, const std::string& algo)
706 const auto& a = aut->as<Aut>();
707 return ::vcsn::scc(a, algo);
717 template <Automaton Aut>
718 std::size_t num_components(const scc_automaton<Aut>& aut)
720 return aut->num_components();
723 template <Automaton Aut>
724 std::size_t num_components(const Aut&)
726 raise("num_components: requires an scc_automaton");
734 template <Automaton Aut>
735 std::size_t num_components(const automaton& aut)
737 const auto& a = aut->as<Aut>();
738 return ::vcsn::num_components(a);
751 template <Automaton Aut>
752 filter_automaton<scc_automaton<Aut>>
753 component(const scc_automaton<Aut>& aut, unsigned num)
755 return vcsn::filter(aut, aut->component(num));
758 template <Automaton Aut>
760 component(const Aut&, unsigned)
762 raise("component: requires an scc_automaton");
770 template <Automaton Aut, typename Unsigned>
771 automaton component(const automaton& aut, unsigned num)
773 const auto& a = aut->as<Aut>();
774 return ::vcsn::component(a, num);
786 template <Automaton Aut>
787 partition_automaton<scc_automaton<Aut>>
788 condense(const scc_automaton<Aut>& aut)
790 auto res = make_shared_ptr<partition_automaton<scc_automaton<Aut>>>(aut);
791 using state_t = state_t_of<Aut>;
793 // State of aut -> state(component) of new automaton.
794 auto map = std::unordered_map<state_t, state_t>
796 {aut->pre(), res->pre()},
797 {aut->post(), res->post()},
800 // Add states to new automaton.
801 for (const auto& com : aut->components())
803 state_t new_state = res->new_state(com);
808 // Add transitions to new automaton.
809 for (auto t: all_transitions(aut))
811 auto s = map[aut->src_of(t)];
812 auto d = map[aut->dst_of(t)];
814 res->add_transition(s, d, aut->label_of(t), aut->weight_of(t));
819 template <Automaton Aut>
820 partition_automaton<Aut>
823 raise("condense: requires an scc_automaton");
831 template <Automaton Aut>
832 automaton condense(const automaton& aut)
834 const auto& a = aut->as<Aut>();
835 return ::vcsn::condense(a);
std::unordered_set< state_t_of< Aut >> component_t
A strongly-connected component: set of states.
detail::components_t< Aut > components_t
Request the Kosaraju's algorithm to compute the SCCs.
Aut transpose(const transpose_automaton< Aut > &aut)
state_t_of< Aut > state_t
reverse_postorder_impl(const Aut &aut)
std::vector< component_t< Aut >> components_t
A set of strongly-connected components.
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
#define BUILTIN_UNREACHABLE()
state_t_of< Aut > state_t
std::unordered_map< state_t, std::size_t > number_
Store the visit order of each state.
detail::component_t< Aut > component_t
std::vector< step_t > dfs_stack_
detail::component_t< Aut > component_t
std::vector< state_t_of< Aut > > reverse_postorder(const Aut &aut)
Get all states in reverse postorder.
state_t_of< Aut > state_t
typename detail::transition_t_of_impl< base_t< ValueSet >>::type transition_t_of
std::vector< state_t > & reverse_post()
Request the Tarjan's algorithm to compute the SCCs, implemented with explicit stack handling...
const components_t & components() const
std::stack< state_t > uncertain_
Stack P contains vertices that have not yet been determined to belong to different strongly connected...
Aggregate an automaton, and forward calls to it.
decltype(out(aut_, state_t{}).begin()) iterator_t
Iterator on outgoing transitions.
components_t components_
All the components.
std::map< state_t, size_t > component_
For each state, its component number.
std::vector< state_t > stack_
List of states in the same the component.
std::ostream & print_set(std::ostream &o, format fmt={}) const
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Tag to request the most appropriate version of an algorithm.
state_t_of< Aut > state_t
scc_automaton< Aut > scc(const Aut &aut, const std::string &algo="auto")
Get scc_automaton from aut.
std::unordered_set< state_t > marked_
Visited states.
detail::components_t< Aut > components_t
ATTRIBUTE_PURE bool has(const boost::container::flat_set< Key, Compare, Allocator > &s, const Key &e)
Whether e is member of s.
std::vector< state_t > rvp_
Revert postorder of dfs.
fresh_automaton_t_of< Aut > aut_of_component(const detail::component_t< Aut > &com, const Aut &aut)
Generate a subautomaton corresponding to an SCC.
step_t(state_t s, iterator_t p, iterator_t e)
transition_t_of< Aut > transition_t
typename detail::state_t_of_impl< base_t< ValueSet >>::type state_t_of
scc_automaton_impl(const automaton_t &input, scc_algo_t algo)
AutOut make_fresh_automaton(const AutIn &model)
Create an empty, mutable, automaton, based on another one.
std::unordered_set< state_t > marked_
Store the visited states.
std::unordered_set< state_t > marked_
const components_t & components()
An input/output format for valuesets.
components_t components_
All components.
Tarjan's algorithm to find all strongly connected components: iterative implementation.
const components_t & components() const
state_t_of< Aut > state_t
scc_algo_t scc_algo(const std::string &algo)
const detail::components_t< Aut > strong_components(const Aut &aut, Tag={})
Find all strongly connected components of aut.
std::unordered_map< state_t, size_t > component_
For each state, its component number.
detail::component_t< Aut > component_t
state_t_of< Aut > state_t
const components_t & components() const
static symbol sname()
Static name.
Class template for strongly-connected-components computations.
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.
std::stack< state_t > unassigned_
Stack S contains all the vertices that have not yet been assigned to a strongly connected component...
detail::components_t< Aut > components_t
A mapping from strings to Values.
std::unordered_map< state_t, std::size_t > low_
low_[s] is minimum of state that it can go.
std::unordered_map< state_t, size_t > preorder_
Provide a variadic mul on top of a binary mul(), and one().
detail::components_t< Aut > components_t
std::vector< state_t > stack_
List of states in the same the component.
detail::component_t< Aut > component_t
detail::component_t< Aut > component_t
detail::components_t< Aut > components_t
An automaton decorator that maps states to their scc-number.
Request the Tarjan's algorithm to compute the SCCs, implemented with recursion.
components_t components_
All components.
components_t components_
All components.
Get all states in reverse postorder using depth first search.
weightset_mixin< detail::r_impl > r