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>
64 rvp_.reserve(aut->num_all_states());
65 for (
auto s : aut->states())
83 auto dst =
aut_->dst_of(t);
100 template <Automaton Aut>
101 std::vector<state_t_of<Aut>>
115 template <Automaton Aut,
typename Tag = auto_tag>
126 template <Automaton Aut>
140 for (
auto s :
aut_->states())
141 if (!
has(component_, s))
149 preorder_[s] = count_;
156 if (!
has(preorder_, dst))
158 else if (!
has(component_, dst))
160 size_t dstpo = preorder_[dst];
161 while (dstpo < preorder_[uncertain_.top()])
165 if (s == uncertain_.top())
168 auto scc_num = components_.size();
169 components_.emplace_back();
172 !unassigned_.empty();
173 unassigned_.pop(),
r = unassigned_.top())
175 component_[
r] = scc_num;
194 std::size_t count_ = 0;
216 template <Automaton Aut>
229 while (!todo.empty())
231 auto s = todo.back();
250 if (num_ == components_.size())
253 components_[num_].emplace(s);
257 auto dst =
aut_->dst_of(t);
266 std::size_t num_ = 0;
288 template <Automaton Aut>
301 for (
auto s :
aut_->states())
302 if (!
has(number_, s))
314 number_[s] = low_[s] = curr_state_num_++;
315 dfs_stack_.emplace_back(s,
out(
aut_, s).begin(),
out(
aut_, s).end());
317 while (!dfs_stack_.empty())
319 auto& st = dfs_stack_.back();
321 if (st.pos != st.end)
323 auto dst =
aut_->dst_of(*st.pos);
325 if (!
has(number_, dst))
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);
332 else if (low_[dst] < low_[src])
333 low_[src] = low_[dst];
337 if (low_[src] == number_[src])
339 components_.emplace_back();
340 auto& com = components_.back();
351 dfs_stack_.pop_back();
352 if (!dfs_stack_.empty())
354 auto& parent = dfs_stack_.back();
355 if (low_[src] < low_[parent.state])
356 low_[parent.state] = low_[src];
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();
391 : state{s}, pos{p}, end{e} {}
414 template <Automaton Aut>
425 for (
auto s : aut_->states())
438 std::size_t
min = curr_state_num_++;
439 low_.emplace(s, min);
443 for (
auto t :
out(aut_, s))
445 auto dst = aut_->dst_of(t);
457 components_.emplace_back();
458 auto& com = components_.back();
467 low_[w] = std::numeric_limits<size_t>::max();
476 std::size_t curr_state_num_ = 0;
483 std::unordered_map<state_t, std::size_t>
low_;
496 template <Automaton Aut>
498 :
public scc_impl<Aut, tarjan_iterative_tag>
501 using super_t::super_t;
523 "strongly connected components algorithm",
528 {
"tarjan",
"tarjan,iterative"},
531 {
"tarjan_iterative",
"tarjan,iterative"},
532 {
"tarjan_recursive",
"tarjan,recursive"},
542 template <Automaton Aut,
typename Tag = auto_tag>
553 template <Automaton Aut>
575 template <Automaton Aut>
580 using res_t = decltype(
res);
582 auto s0 = *com.begin();
583 map[s0] =
res->new_state();
584 res->set_initial(
map[s0]);
588 map[s] =
res->new_state();
589 for (
auto t :
out(aut, s))
591 auto dst = aut->dst_of(t);
595 map[dst] =
res->new_state();
596 res->new_transition(
map[s],
map[dst], aut->label_of(t));
609 template <Automaton Aut>
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])
639 static auto res =
symbol{
"scc_automaton<" 646 o <<
"scc_automaton<";
647 aut_->print_set(o, fmt);
651 bool state_has_name(state_t) const 656 std::ostream& print_state_name(state_t s, std::ostream& o, 660 o << component_.at(s) << '.
'; 661 aut_->print_state_name(s, o, fmt, true); 665 const component_t& component(unsigned num) const 667 VCSN_REQUIRE(num < components_.size(), 668 "component: invalid component number: ", 669 num, ": there are ", components_.size(), " components"); 670 return components_[num]; 673 const components_t& components() const 678 size_t num_components() const 680 return components_.size(); 686 std::map<state_t, size_t> component_; 687 components_t components_; 691 template <Automaton Aut> 692 using scc_automaton = std::shared_ptr<detail::scc_automaton_impl<Aut>>; 695 template <Automaton Aut> 697 scc(const Aut& aut, const std::string& algo = "auto") 699 return make_shared_ptr<scc_automaton<Aut>>(aut, scc_algo(algo)); 707 template <Automaton Aut, typename String> 708 automaton scc(const automaton& aut, const std::string& algo) 710 const auto& a = aut->as<Aut>(); 711 return ::vcsn::scc(a, algo); 721 template <Automaton Aut> 722 std::size_t num_components(const scc_automaton<Aut>& aut) 724 return aut->num_components(); 727 template <Automaton Aut> 728 std::size_t num_components(const Aut&) 730 raise("num_components: requires an scc_automaton"); 738 template <Automaton Aut> 739 std::size_t num_components(const automaton& aut) 741 const auto& a = aut->as<Aut>(); 742 return ::vcsn::num_components(a); 755 template <Automaton Aut> 756 filter_automaton<scc_automaton<Aut>> 757 component(const scc_automaton<Aut>& aut, unsigned num) 759 return vcsn::filter(aut, aut->component(num)); 762 template <Automaton Aut> 764 component(const Aut&, unsigned) 766 raise("component: requires an scc_automaton"); 774 template <Automaton Aut, typename Unsigned> 775 automaton component(const automaton& aut, unsigned num) 777 const auto& a = aut->as<Aut>(); 778 return ::vcsn::component(a, num); 790 template <Automaton Aut> 791 partition_automaton<scc_automaton<Aut>> 792 condense(const scc_automaton<Aut>& aut) 794 auto res = make_shared_ptr<partition_automaton<scc_automaton<Aut>>>(aut); 795 using state_t = state_t_of<Aut>; 797 // State of aut -> state(component) of new automaton. 798 auto map = std::unordered_map<state_t, state_t> 800 {aut->pre(), res->pre()}, 801 {aut->post(), res->post()}, 804 // Add states to new automaton. 805 for (const auto& com : aut->components()) 807 state_t new_state = res->new_state(com); 812 // Add transitions to new automaton. 813 for (auto t: all_transitions(aut)) 815 auto s = map[aut->src_of(t)]; 816 auto d = map[aut->dst_of(t)]; 818 res->add_transition(s, d, aut->label_of(t), aut->weight_of(t)); 823 template <Automaton Aut> 824 partition_automaton<Aut> 827 raise("condense: requires an scc_automaton"); 835 template <Automaton Aut> 836 automaton condense(const automaton& aut) 838 const auto& a = aut->as<Aut>(); 839 return ::vcsn::condense(a); Aut transpose(const transpose_automaton< Aut > &aut)
The transpose of a transpose automaton is the original automaton.
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.
weightset_mixin< detail::r_impl > r
std::vector< state_t > stack_
List of states in the same the component.
state_t_of< Aut > state_t
std::unordered_set< state_t > marked_
Store the visited states.
state_t_of< Aut > state_t
std::ostream & print_set(std::ostream &o, format fmt={}) const
detail::component_t< Aut > component_t
std::vector< state_t_of< Aut > > reverse_postorder(const Aut &aut)
Get all states in reverse postorder.
typename detail::transition_t_of_impl< base_t< ValueSet > >::type transition_t_of
typename detail::state_t_of_impl< base_t< ValueSet > >::type state_t_of
detail::component_t< Aut > component_t
const components_t & components() const
Class template for strongly-connected-components computations.
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.
std::stack< state_t > uncertain_
Stack P contains vertices that have not yet been determined to belong to different strongly connected...
std::unordered_map< state_t, std::size_t > low_
low_[s] is minimum of state that it can go.
std::unordered_set< state_t > marked_
Tarjan's algorithm to find all strongly connected components: iterative implementation.
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
scc_algo_t scc_algo(const std::string &algo)
static symbol sname()
Static name.
scc_automaton_impl(const automaton_t &input, scc_algo_t algo)
components_t components_
All components.
std::unordered_set< state_t_of< Aut > > component_t
A strongly-connected component: set of states.
An automaton decorator that maps states to their scc-number.
An input/output format for valuesets.
Provide a variadic mul on top of a binary mul(), and one().
std::vector< state_t > & reverse_post()
components_t components_
All components.
std::unordered_map< state_t, size_t > preorder_
Request the Kosaraju's algorithm to compute the SCCs.
std::unordered_set< state_t > marked_
Visited states.
Tag to request the most appropriate version of an algorithm.
detail::components_t< Aut > components_t
Get all states in reverse postorder using depth first search.
std::vector< state_t > rvp_
Revert postorder of dfs.
scc_automaton< Aut > scc(const Aut &aut, const std::string &algo="auto")
Get scc_automaton from aut.
Request the Tarjan's algorithm to compute the SCCs, implemented with recursion.
detail::component_t< Aut > component_t
Request the Tarjan's algorithm to compute the SCCs, implemented with explicit stack handling...
std::vector< step_t > dfs_stack_
state_t_of< Aut > state_t
detail::component_t< Aut > component_t
detail::components_t< Aut > components_t
AutOut make_fresh_automaton(const AutIn &model)
Create an empty, mutable, automaton, based on another one.
Aggregate an automaton, and forward calls to it.
std::unordered_map< state_t, size_t > component_
For each state, its component number.
components_t components_
All the components.
std::stack< state_t > unassigned_
Stack S contains all the vertices that have not yet been assigned to a strongly connected component...
detail::component_t< Aut > component_t
transition_t_of< Aut > transition_t
A mapping from strings to Values.
components_t components_
All components.
detail::components_t< Aut > components_t
state_t_of< Aut > state_t
const components_t & components()
decltype(out(aut_, state_t{}).begin()) iterator_t
Iterator on outgoing transitions.
const components_t & components() const
step_t(state_t s, iterator_t p, iterator_t e)
state_t_of< Aut > state_t
const components_t & components() const
detail::components_t< Aut > components_t
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.
typename Aut::element_type::template fresh_automaton_t< Context > fresh_automaton_t_of
Given an automaton type, the type of its copies.
state_t_of< Aut > state_t
reverse_postorder_impl(const Aut &aut)
#define BUILTIN_UNREACHABLE()
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.
std::unordered_map< state_t, std::size_t > number_
Store the visit order of each state.
std::vector< state_t > stack_
List of states in the same the component.
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.