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_;
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();
246 if (num_ == components_.size())
249 components_[num_].emplace(s);
253 auto dst =
aut_->dst_of(t);
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())
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);
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>
549 template <Automaton Aut>
571 template <Automaton 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); static symbol sname()
Static name.
decltype(out(aut_, state_t{}).begin()) iterator_t
Iterator on outgoing transitions.
std::ostream & print_set(std::ostream &o, format fmt={}) const
ATTRIBUTE_PURE bool has(const boost::container::flat_set< Key, Compare, Allocator > &s, const Key &e)
Whether e is member of s.
transition_t_of< Aut > transition_t
state_t_of< Aut > state_t
std::vector< state_t > stack_
List of states in the same the component.
Request the Tarjan's algorithm to compute the SCCs, implemented with recursion.
std::vector< step_t > dfs_stack_
reverse_postorder_impl(const Aut &aut)
components_t components_
All components.
Request the Tarjan's algorithm to compute the SCCs, implemented with explicit stack handling...
std::unordered_map< state_t, std::size_t > low_
low_[s] is minimum of state that it can go.
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.
detail::components_t< Aut > components_t
step_t(state_t s, iterator_t p, iterator_t e)
Aggregate an automaton, and forward calls to it.
const detail::components_t< Aut > strong_components(const Aut &aut, Tag={})
Find all strongly connected components of aut.
fresh_automaton_t_of< Aut > aut_of_component(const detail::component_t< Aut > &com, const Aut &aut)
Generate a subautomaton corresponding to an SCC.
std::vector< component_t< Aut > > components_t
A set of strongly-connected components.
AutOut make_fresh_automaton(const AutIn &model)
Create an empty, mutable, automaton, based on another one.
std::unordered_set< state_t_of< Aut > > component_t
A strongly-connected component: set of states.
state_t_of< Aut > state_t
detail::component_t< Aut > component_t
state_t_of< Aut > state_t
detail::component_t< Aut > component_t
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
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.
const components_t & components()
typename detail::state_t_of_impl< base_t< ValueSet > >::type state_t_of
detail::components_t< Aut > components_t
weightset_mixin< detail::r_impl > r
std::unordered_map< state_t, size_t > component_
For each state, its component number.
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
#define BUILTIN_UNREACHABLE()
std::unordered_map< state_t, std::size_t > number_
Store the visit order of each state.
detail::components_t< Aut > components_t
std::unordered_set< state_t > marked_
Visited states.
std::vector< state_t > & reverse_post()
std::vector< state_t > stack_
List of states in the same the component.
detail::components_t< Aut > components_t
std::unordered_set< state_t > marked_
Store the visited states.
An automaton decorator that maps states to their scc-number.
state_t_of< Aut > state_t
std::unordered_map< state_t, size_t > preorder_
state_t_of< Aut > state_t
detail::component_t< Aut > component_t
std::unordered_set< state_t > marked_
detail::component_t< Aut > component_t
An input/output format for valuesets.
Provide a variadic mul on top of a binary mul(), and one().
std::stack< state_t > uncertain_
Stack P contains vertices that have not yet been determined to belong to different strongly connected...
detail::component_t< Aut > component_t
Aut transpose(const transpose_automaton< Aut > &aut)
The transpose of a transpose automaton is the original automaton.
std::stack< state_t > unassigned_
Stack S contains all the vertices that have not yet been assigned to a strongly connected component...
state_t_of< Aut > state_t
detail::components_t< Aut > components_t
typename detail::transition_t_of_impl< base_t< ValueSet > >::type transition_t_of
typename Aut::element_type::template fresh_automaton_t< Context > fresh_automaton_t_of
Given an automaton type, the type of its copies.
components_t components_
All components.
scc_algo_t scc_algo(const std::string &algo)
scc_automaton_impl(const automaton_t &input, scc_algo_t algo)
A mapping from strings to Values.
components_t components_
All components.
const components_t & components() const
std::vector< state_t > rvp_
Revert postorder of dfs.
Class template for strongly-connected-components computations.
const components_t & components() const
const components_t & components() const
components_t components_
All the components.
std::vector< state_t_of< Aut > > reverse_postorder(const Aut &aut)
Get all states in reverse postorder.
scc_automaton< Aut > scc(const Aut &aut, const std::string &algo="auto")
Get scc_automaton from aut.
Tarjan's algorithm to find all strongly connected components: iterative implementation.
Request the Kosaraju's algorithm to compute the SCCs.
Tag to request the most appropriate version of an algorithm.
Get all states in reverse postorder using depth first search.