Awali
Another Weighted Automata library
scc.hh
Go to the documentation of this file.
1 // This file is part of Awali.
2 // Copyright 2016-2022 Sylvain Lombardy, Victor Marsault, Jacques Sakarovitch
3 //
4 // Awali is a free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 #ifndef STTC_ALGOS_FACTOR_HH
18 #define STTC_ALGOS_FACTOR_HH
19 
20 #include <vector>
21 #include <unordered_map>
22 
24 
25 namespace awali { namespace sttc {
26 
27  namespace internal {
28 
29  template <typename Aut>
30  class tarjaner_t {
31 
32  using automaton_t = Aut;
33  using weight_t = weight_t_of<automaton_t>;
34  using label_t = label_t_of<automaton_t>;
35  using context_t= context_t_of<automaton_t>;
36 
37 
38  using result_t = std::pair<
39  std::unordered_map<state_t, unsigned int>, // state -> scc
40  std::vector<std::vector<state_t>> >; // scc -> state
41 
42  typedef struct {
43  state_t id;
44  unsigned int index;
45  unsigned int current_root;
46  bool onstack;
47  } tarjan_state_t;
48 
49 
50  typedef struct {
51  std::stack<state_t> stack;
52  std::unordered_map<state_t, tarjan_state_t*> map; /* Coloring of visited states */
53  std::unordered_map<state_t, unsigned int> scc_of;
54  std::vector<std::vector<state_t>> states_of;
55  unsigned int cur_num = 0; /* Number of visited states */
56  unsigned int cur_scc = 2; /* Number of created scc.
57  Starts at 2 in order to reserve 0 and 1 for
58  the scc of subliminal states in condensation */
59  } tarjan_data_t;
60 
61  automaton_t aut;
62  tarjan_data_t data;
63 
64 
65 
66  std::vector<state_t> successors (automaton_t aut, state_t stt) {
67  std::vector<state_t> res;
68  for (transition_t tr : aut->out(stt))
69  res.push_back(aut->dst_of(tr));
70  return res;
71  }
72 
73  public:
74  void
75  visit_recursive (const automaton_t& aut, state_t stt)
76  {
77  tarjan_state_t* cur = new tarjan_state_t
78  { stt, data.cur_num, data.cur_num, true };
79  data.map.insert(std::pair<state_t, tarjan_state_t*>{stt,cur});
80  data.stack.push(stt);
81  data.cur_num++;
82 
83  for (state_t succ : successors(aut, stt)) {
84  auto it= data.map.find(succ);
85  if (it == data.map.end()) {
86  visit_recursive (aut, succ);
87  it= data.map.find(succ);
88  }
89  if (it->second->onstack)
90  cur->current_root = utils::min(cur->current_root,
91  it->second->current_root);
92  // else do nothing: successor was already put on stack and removed
93  }
94 
95  if (cur->index == cur->current_root) {
96  state_t top;
97  data.states_of.push_back({});
98  std::vector<state_t>& back = data.states_of.back();
99  do {
100  top= data.stack.top();
101  data.stack.pop();
102  data.map[top]->onstack= false;
103  back.push_back(top);
104  data.scc_of[top]= data.cur_scc;
105  } while (top != cur->id);
106  data.cur_scc++;
107  }
108 
109  }
110 
111  void
113  {
114  for(state_t stt : aut->states())
115  if (data.map.find(stt) == data.map.end())
116  visit_recursive(aut, stt);
117  }
118 
119 
120  typedef struct {
121  tarjan_state_t* src;
122  std::vector<state_t> dst_to_treat;
123  long unsigned int remaining;
124  tarjan_state_t* caller;
125  } token_t ;
126 
127  inline
128  token_t make_token(tarjan_state_t* t, std::vector<state_t> v,
129  tarjan_state_t* c = nullptr)
130  {
131  return token_t{t, v, v.size(), c};
132  }
133 
134 
135 
136  void
138  {
139 
140  if (data.map.find(stt) != data.map.end())
141  return;
142  std::stack<token_t> tstack; /* Stack of what would be recursive calls */
143  {
144  tarjan_state_t* t_stt= new tarjan_state_t
145  { stt, data.cur_num, data.cur_num, true };
146  data.cur_num++;
147  data.map.insert(std::pair<state_t, tarjan_state_t*>(stt, t_stt));
148  tstack.push( make_token(t_stt, std::move(successors(aut, stt))) );
149  data.stack.push(stt);
150  }
151  while (!tstack.empty())
152  {
153  token_t& token= tstack.top();
154  // std::cerr << "Treating " << (token.src->id-2) << "; "
155  // << token.remaining << " successors remains."
156  // << std::endl;
157  if ( token.remaining > 0)
158  {
159  state_t dst= token.dst_to_treat[--token.remaining];
160  auto it = data.map.find(dst);
161  if ( it == data.map.end()) {
162  // std::cerr << "\tPushing " << (dst-2) << "." << std::endl;
163  tarjan_state_t* t_dst=
164  new tarjan_state_t{ dst, data.cur_num, data.cur_num, true };
165  data.cur_num++;
166  data.map.insert(std::pair<state_t, tarjan_state_t*>(dst, t_dst));
167  tstack.push( make_token(t_dst, std::move(successors(aut, dst)), token.src) );
168  data.stack.push(dst);
169  } else if ( it->second->onstack ) {
170  token.src->current_root = utils::min(token.src->current_root,
171  it->second->current_root);
172  // std::cerr << "\t\tNew root: " << token.src->current_root << "." << std::endl;
173  }
174  }
175  else
176  {
177  if (token.caller != nullptr) {
178  token.caller->current_root =
179  utils::min( token.caller->current_root,
180  token.src->current_root );
181  }
182  if (token.src->index == token.src->current_root)
183  {
184  data.states_of.push_back({});
185  std::vector<state_t>& back = data.states_of.back();
186  state_t bot = token.src->id;
187  state_t top;
188  do {
189  top= data.stack.top();
190  data.stack.pop();
191  data.map[top]->onstack= false;
192  back.push_back(top);
193  data.scc_of[top]= data.cur_scc;
194  } while (top != bot);
195  data.cur_scc++;
196  }
197  tstack.pop();
198  }
199  }
200  }
201 
202  void
204  {
205  for(state_t stt : aut->states())
206  visit_iterative(stt);
207  }
208 
209 
210  //This function should not be called before iterative or recursive
211  void
213  {
214  data.scc_of[0]=0;
215  data.scc_of[1]=1;
216 
217  auto it = data.states_of.begin();
218  data.states_of.insert(it,{1});
219 
220  it = data.states_of.begin();
221  data.states_of.insert(it,{0});
222  }
223 
224 
225  //This function should not be called before iterative or recursive
226  //and assumes subliminal sccs/states are properly mapped.
227  automaton_t
229  {
230  automaton_t out= make_mutable_automaton<context_t>(aut->context());
231  auto history = std::make_shared<partition_history<automaton_t>>(aut);
232  out->set_history(history);
233  unsigned int max= data.states_of.size();
234  for (unsigned int i=2; i<max; i++) {
235  out->add_state();
236  }
237  unsigned int i = 0;
238  for (std::vector<state_t> scc : data.states_of) {
239  std::set<state_t> hist;
240  hist.insert(scc.begin(), scc.end());
241  history->add_state(i, std::move(hist));
242  i++;
243  }
244 
245  for (auto it = data.scc_of.cbegin(); it != data.scc_of.cend() ; it++) {
246  for (transition_t t: aut->all_out(it->first)) {
247  state_t dest = aut->dst_of(t);
248  weight_t w= aut->weight_of(t);
249  label_t l= aut->label_of(t);
250  out->add_transition(it->second, data.scc_of[dest], l, w);
251  }
252  }
253  return out;
254  }
255 
256 
257  //Once this function is called, the object tarjaner_t should not be
258  //used any longer
259  result_t
261  {
262  return { std::move(data.scc_of), std::move(data.states_of) };
263  }
264 
265 
266 
267  tarjaner_t(automaton_t a) : aut(a)
268  {
269  size_t n=aut->num_states()+2;
270  data.map.reserve(n);
271  data.scc_of.reserve(n);
272  }
273 
275  {
276  for (auto it= data.map.cbegin(); it != data.map.cend(); it++)
277  delete (it->second);
278  }
279 
280  };// end of class tarjaner_t
281 
282 
283  }
284 
293  template <typename Aut>
294  std::pair< std::unordered_map<state_t, unsigned int>,
295  std::vector<std::vector<state_t>> >
296  scc_recursive (Aut aut)
297  {
298  internal::tarjaner_t<Aut> tarjaner(aut);
299  tarjaner.compute_sccs_recursive();
300  return tarjaner.get_result();
301  }
302 
303 
311  template <typename Aut>
312  std::pair< std::unordered_map<state_t, unsigned int>,
313  std::vector<std::vector<state_t>> >
314  scc_iterative (Aut aut)
315  {
316  internal::tarjaner_t<Aut> tarjaner(aut);
317  tarjaner.compute_sccs_iterative();
318  return tarjaner.get_result();
319  }
320 
321 
340  template <typename Aut>
341  std::pair< Aut, std::pair< std::unordered_map<state_t, unsigned int>,
342  std::vector<std::vector<state_t>> > >
343  condensation (Aut aut)
344  {
345  internal::tarjaner_t<Aut> tarjaner(aut);
346  tarjaner.compute_sccs_iterative();
347  tarjaner.add_subliminal_sccs();
348  Aut out = tarjaner.condensation();
349  return {out, tarjaner.get_result()};
350  }
351 
359  template <typename Aut>
360  std::vector<state_t>
361  scc_of (Aut aut, state_t s)
362  {
363  internal::tarjaner_t<Aut> tarjaner(aut);
364  tarjaner.visit_iterative(s);
365  auto res= tarjaner.get_result();
366  return std::move(res.second[res.second.size()-1]);
367  }
368 
369 
370 }}// end of ns awali::sttc
371 
372 #endif
The semiring of complex numbers.
Definition: c.hh:44
~tarjaner_t()
Definition: scc.hh:274
tarjan_state_t * src
Definition: scc.hh:121
automaton_t condensation()
Definition: scc.hh:228
void add_subliminal_sccs()
Definition: scc.hh:212
tarjaner_t(automaton_t a)
Definition: scc.hh:267
void visit_iterative(state_t stt)
Definition: scc.hh:137
long unsigned int remaining
Definition: scc.hh:123
tarjan_state_t * caller
Definition: scc.hh:124
void compute_sccs_iterative()
Definition: scc.hh:203
std::vector< state_t > dst_to_treat
Definition: scc.hh:122
result_t get_result()
Definition: scc.hh:260
token_t make_token(tarjan_state_t *t, std::vector< state_t > v, tarjan_state_t *c=nullptr)
Definition: scc.hh:128
void visit_recursive(const automaton_t &aut, state_t stt)
Definition: scc.hh:75
void compute_sccs_recursive()
Definition: scc.hh:112
The semiring of Natural numbers.
Definition: n.hh:34
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:134
static constexpr TOP< void > top
Definition: priority.hh:93
typename internal::label_t_of_impl< internal::base_t< ValueSet > >::type label_t_of
Helper to retrieve the type of the labels of a value set.
Definition: traits.hh:71
std::pair< std::unordered_map< state_t, unsigned int >, std::vector< std::vector< state_t > > > scc_iterative(Aut aut)
Iterative computation of strongly connected components.
Definition: scc.hh:314
std::vector< state_t > scc_of(Aut aut, state_t s)
Computes the strongly connected component of a state.
Definition: scc.hh:361
typename internal::weight_t_of_impl< internal::base_t< ValueSet > >::type weight_t_of
Helper to retrieve the type of the weights of a value set.
Definition: traits.hh:81
typename internal::context_t_of_impl< internal::base_t< ValueSet > >::type context_t_of
Helper to retrieve the type of the context of a value set.
Definition: traits.hh:66
std::pair< Aut, std::pair< std::unordered_map< state_t, unsigned int >, std::vector< std::vector< state_t > > > > condensation(Aut aut)
Condense each strongly connected component to a state.
Definition: scc.hh:343
std::pair< std::unordered_map< state_t, unsigned int >, std::vector< std::vector< state_t > > > scc_recursive(Aut aut)
Recursive computation of strongly connected components.
Definition: scc.hh:296
pair_automaton< Aut > pair(const Aut &aut, bool keep_initials=false)
Definition: synchronizing_word.hh:266
ATTRIBUTE_CONST int max(int a, int b)
Definition: arith.hh:54
ATTRIBUTE_CONST int min(int a, int b)
Definition: arith.hh:48
Main namespace of Awali.
Definition: ato.hh:22
unsigned state_t
Definition: types.hh:21
unsigned transition_t
Definition: types.hh:22