Awali
Another Weighted Automata library
determinize.hxx
Go to the documentation of this file.
1 // This file is part of Awali.
2 // Copyright 2016-2021 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 AWALI_ALGOS_DETERMINIZE_HXX
18 # define AWALI_ALGOS_DETERMINIZE_HXX
19 
20 # include <set>
21 # include <stack>
22 # include <string>
23 # include <type_traits>
24 # include <queue>
25 # include <limits>
26 
28 #include <awali/sttc/ctx/traits.hh>
29 #include <awali/sttc/misc/map.hh> // sttc::has
30 #include <awali/sttc/misc/raise.hh> // b
32 #include <awali/sttc/misc/unordered_map.hh> // sttc::has
33 #include <awali/sttc/weightset/b.hh> // b
35 
36 namespace awali { namespace sttc {
37 
38  /*----------------------.
39  | subset construction. |
40  `----------------------*/
41  namespace internal
42  {
48  template <typename Aut,unsigned N>
50  {
51  static_assert(labelset_t_of<Aut>::is_free(),
52  "determinize: requires free labelset");
53  static_assert(std::is_same<weightset_t_of<Aut>, b>::value,
54  "determinize: requires Boolean weights");
55 
56  public:
57  using automaton_t = Aut;
62  using state_set = std::bitset<N>;
63 
67  : input_(a)
68  , output_(make_mutable_automaton<context_t>(a->context()))
69  {
70  // Input final states.
71  for (auto t : input_->final_transitions())
72  finals_.set(input_->src_of(t));
73 
74  // The input initial states.
75  //
76  // We could start with pre only, but then on an input
77  // automaton without initial state, we would produce an empty
78  // automaton (no states). This would not conform to Jacques'
79  // definition of determinization.
80  state_set pre;
81  pre.set(input_->pre());
82  todo_.push(pre);
83  }
84 
87  state_t state(const state_set& ss)
88  {
89  // Benches show that the map_.emplace technique is slower, and
90  // then that operator[] is faster than emplace.
91  state_t res;
92  auto i = map_.find(ss);
93  if (i == std::end(map_))
94  {
95  res = output_->add_state();
96  map_[ss] = res;
97  if ((ss & finals_).any())
98  output_->set_final(res);
99 
100  todo_.push(ss);
101  }
102  else
103  res = i->second;
104  return res;
105  }
106 
109  {
110  bool first=true;
111  std::map<label_t, state_set, internal::less<labelset_t_of<Aut>>> ml;
112  while (!todo_.empty())
113  {
114  auto ss = std::move(todo_.top());
115  state_t src;
116  if(first) {
117  src = output_->pre();
118  first=false;
119  }
120  else
121  src = state(ss);
122  todo_.pop();
123 
124  ml.clear();
125  auto it=internal::get_iterator(ss);
126  while(it.has_next())
127  {
128  auto s=it.next();
129  // Cache the output transitions of state s.
130  auto i = successors_.find(s);
131  if (i == successors_.end())
132  {
133  i = successors_.emplace(s, label_map_t{}).first;
134  auto& j = i->second;
135  for (auto t : input_->out(s))
136  {
137  auto l = input_->label_of(t);
138  j[l].set(input_->dst_of(t));
139  }
140  }
141 
142  // Store in ml the possible destination per label.
143  for (const auto& p : i->second)
144  {
145  auto j = ml.find(p.first);
146  if (j == ml.end())
147  ml[p.first] = p.second;
148  else
149  j->second |= p.second;
150  }
151  }
152 
153  // Outgoing transitions from the current (result) state.
154  for (const auto& e : ml)
155  output_->new_transition(src, state(e.second), e.first);
156  }
157  return output_;
158  }
159 
160  void set_history() {
161  auto history = std::make_shared<partition_history<automaton_t>>(input_);
162  output_->set_history(history);
163  if(!input_->get_name().empty()) {
164  output_->set_desc("Determinization of "+input_->get_name());
165  output_->set_name("det-"+input_->get_name());
166  }
167  else {
168  output_->set_desc("Determinization");
169  output_->set_name("det");
170  }
171  for (const auto& p: map_)
172  {
173  std::set<state_t> from;
174  const auto& ss = p.first;
175  auto it=internal::get_iterator(ss);
176  while(it.has_next())
177  from.emplace(it.next());
178  history->add_state(p.second, std::move(from));
179  }
180  }
181 
182  private:
184  using map = std::unordered_map<state_set, state_t>;
185  map map_;
186 
188  automaton_t input_;
190  automaton_nocv_t output_;
191 
193  using stack = std::stack<state_set>;
194  stack todo_;
195 
197  state_set finals_;
198 
200  using label_map_t = std::unordered_map<label_t, state_set>;
201  using successors_t = std::unordered_map<state_t, label_map_t>;
202  successors_t successors_;
203  };
204 
205 
211  template <typename Aut>
213  {
214  static_assert(labelset_t_of<Aut>::is_free(),
215  "determinize: requires free labelset");
216  static_assert(std::is_same<weightset_t_of<Aut>, b>::value,
217  "determinize: requires Boolean weights");
218 
219  public:
220  using automaton_t = Aut;
224 
226  using state_set = std::set<state_t>;
227 
231  : input_(a)
232  , output_(make_mutable_automaton<context_t>(a->context()))
233  {
234  // Input final states.
235  for (auto t : input_->final_transitions())
236  finals_.emplace(input_->src_of(t));
237 
238  // The input initial states.
239  //
240  // We could start with pre only, but then on an input
241  // automaton without initial state, we would produce an empty
242  // automaton (no states). This would not conform to Jacques'
243  // definition of determinization.
244  state_set pre;
245  pre.emplace(input_->pre());
246  todo_.push(pre);
247  }
248 
252  {
253  state_t res;
254  auto i = map_.find(ss);
255  if (i == std::end(map_))
256  {
257  res = output_->add_state();
258  map_[ss] = res;
259  todo_.push(ss);
260  }
261  else
262  res = i->second;
263  return res;
264  }
265 
268  {
269  bool first=true;
270  std::map<label_t, state_set, internal::less<labelset_t_of<Aut>>> ml;
271  while (!todo_.empty())
272  {
273  auto ss = std::move(todo_.top());
274  state_t src;
275  if(first) {
276  src = output_->pre();
277  first=false;
278  }
279  else
280  src = state(ss);
281  todo_.pop();
282 
283  ml.clear();
284  bool isfinal=false;
285  for (auto s : ss) {
286  for(auto t : input_->all_out(s))
287  if(input_->dst_of(t)==input_->post())
288  isfinal=true;
289  else {
290  auto j = ml.find(input_->label_of(t));
291  if (j == ml.end()) {
292  state_set st;
293  st.emplace(input_->dst_of(t));
294  ml[input_->label_of(t)] = st;
295  }
296  else
297  j->second.emplace(input_->dst_of(t));
298  }
299  }
300  if(isfinal)
301  output_->set_final(src);
302 
303  // Outgoing transitions from the current (result) state.
304  for (const auto& e : ml)
305  output_->new_transition(src, state(e.second), e.first);
306  }
307  return output_;
308  }
309 
310  void set_history() {
311  auto history = std::make_shared<partition_history<automaton_t>>(input_);
312  output_->set_history(history);
313  for (const auto& p: map_)
314  {
315  std::set<state_t> from;
316  const auto& ss = p.first;
317  for (auto s : ss)
318  from.emplace(s);
319  history->add_state(p.second, std::move(from));
320  }
321  }
322 
323  private:
325  using map = std::map<state_set, state_t>;
326  map map_;
327 
329  automaton_t input_;
331  automaton_nocv_t output_;
332 
334  using stack = std::stack<state_set>;
335  stack todo_;
336 
338  state_set finals_;
339 
341  using label_map_t = std::map<label_t, state_set>;
342  };
343  }
344 
345  /*-------------------------------------.
346  | universal weighted determinization. |
347  `--------------------------------------*/
348  namespace internal
349  {
359  template <typename Aut>
361  {
362  static_assert(labelset_t_of<Aut>::is_free(),
363  "determinize: requires free labelset");
364 
365  public:
366  using automaton_t = Aut;
367 
371 
373  struct stateset
374  {
375  stateset(const automaton_t& aut)
376  : aut_(aut)
377  {}
378 
379  using value_t = state_t;
380  using kind_t = void;
381  static bool less_than(state_t l, state_t r)
382  {
383  return l < r;
384  }
385 
387  };
388 
391 
395  : input_(a)
396  , output_(make_mutable_automaton(a->context()))
397  {}
398 
399  // Initialize initial state of new weighted automaton.
401  {
402  state_name_t ss;
403  for (auto t : input_->initial_transitions())
404  ss.emplace(input_->dst_of(t), input_->weight_of(t));
405  output_->set_initial(state_(ss));
406  }
407 
410  {
412 
413  // label -> <destination, sum of weights>.
415  std::pair<state_name_t, weight_t>,
417  while (!todo_.empty())
418  {
419  auto ss = std::move(todo_.front());
420  todo_.pop();
421  auto src = map_[ss];
422 
423  dests.clear();
424  for (const auto& p : ss)
425  {
426  auto s = p.first;
427  auto v = p.second;
428  for (auto t : input_->out(s))
429  {
430  auto l = input_->label_of(t);
431  auto dst = input_->dst_of(t);
432  auto w = ws_.mul(v, input_->weight_of(t));
433 
434  // For each letter, update destination state, and
435  // sum of weights.
436  if (dests.find(l)==dests.end())
437  dests.emplace(l, make_pair(ns_.zero(), ws_.zero()));
438  auto& d = dests[l];
439  ns_.add_here(d.first, dst, w);
440  d.second = ws_.add(d.second, w);
441  }
442  }
443  for (auto& d : dests)
444  output_->new_transition(src,
445  state_(d.second.first),
446  d.first);
447  }
448  return output_;
449  }
450 
451  private:
454  state_t state_(const state_name_t& name)
455  {
456  // Benches show that the map_.emplace technique is slower, and
457  // then that operator[] is faster than emplace.
458  state_t res;
459  auto i = map_.find(name);
460  if (i == std::end(map_))
461  {
462  res = output_->add_state();
463  map_[name] = res;
464  for (const auto& p : name)
465  if (input_->is_final(p.first))
466  output_->add_final(res,
467  ws_.mul(p.second,
468  input_->get_final_weight(p.first)));
469 
470  todo_.push(name);
471  }
472  else
473  res = i->second;
474  return res;
475  };
476 
478  std::map<state_name_t, state_t, internal::less<state_nameset_t>> map_;
479 
481  automaton_t input_;
482 
484  automaton_t output_;
485 
487  weightset_t ws_ = *input_->weightset();
488 
490  state_nameset_t ns_ = {{stateset(input_), *input_->weightset()}};
491 
495  unsigned state_size_ = input_->max_state() + 1;
496 
498  using queue = std::queue<state_name_t>;
499  queue todo_;
500  };
501  }
502 
503 
504 }}//end of ns awali::stc
505 
506 #endif // !AWALI_ALGOS_DETERMINIZE_HXX
The Boolean semring.
Definition: b.hh:38
carries the algebraic settings of automata
Definition: context.hh:40
The subset construction automaton from another.
Definition: determinize.hxx:50
std::bitset< N > state_set
Set of (input) states.
Definition: determinize.hxx:62
Aut automaton_t
Definition: determinize.hxx:57
determinization_bitset_impl(const automaton_t &a)
Build the determinizer.
Definition: determinize.hxx:66
automaton_nocv_t operator()()
Determinize all accessible states.
Definition: determinize.hxx:108
mutable_automaton< context_t_of< Aut > > automaton_nocv_t
Definition: determinize.hxx:58
state_t state(const state_set &ss)
The state for set of states ss.
Definition: determinize.hxx:87
label_t_of< automaton_t > label_t
Definition: determinize.hxx:59
void set_history()
Definition: determinize.hxx:160
context_t_of< automaton_t > context_t
Definition: determinize.hxx:60
The subset construction automaton from another.
Definition: determinize.hxx:213
determinization_set_impl(const automaton_t &a)
Build the determinizer.
Definition: determinize.hxx:230
Aut automaton_t
Definition: determinize.hxx:220
mutable_automaton< context_t_of< Aut > > automaton_nocv_t
Definition: determinize.hxx:221
void set_history()
Definition: determinize.hxx:310
label_t_of< automaton_t > label_t
Definition: determinize.hxx:222
std::set< state_t > state_set
Set of (input) states.
Definition: determinize.hxx:226
context_t_of< automaton_t > context_t
Definition: determinize.hxx:223
state_t state(const state_set &ss)
The state for set of states ss.
Definition: determinize.hxx:251
automaton_nocv_t operator()()
Determinize all accessible states.
Definition: determinize.hxx:267
The weighted determinization of weighted automaton.
Definition: determinize.hxx:361
void init_initial_state()
Definition: determinize.hxx:400
weight_t_of< automaton_t > weight_t
Definition: determinize.hxx:370
automaton_t operator()()
The determinization of weighted automaton.
Definition: determinize.hxx:409
label_t_of< automaton_t > label_t
Definition: determinize.hxx:368
weightset_t_of< automaton_t > weightset_t
Definition: determinize.hxx:369
detweighted_algo_impl(const automaton_t &a)
Build the weighted determinizer.
Definition: determinize.hxx:394
Aut automaton_t
Definition: determinize.hxx:366
typename state_nameset_t::value_t state_name_t
Definition: determinize.hxx:390
polynomialset< context< stateset, weightset_t > > state_nameset_t
Definition: determinize.hxx:389
adapter of std::less to wrap less_than method of valuesets
Definition: map.hh:61
const weightset_ptr & weightset() const
Definition: polynomialset.hh:107
std::map< label_t, weight_t, internal::less< labelset_t > > value_t
Definition: polynomialset.hh:83
value_t & add_here(value_t &v, const value_t &p) const
v += p.
Definition: polynomialset.hh:130
const value_t & zero() const
Definition: polynomialset.hh:353
The semiring of floating Numbers.
Definition: r.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
json_ast_t from(std::istream &i)
Builds a json_ast_t from an input stream.
static constexpr TOP< void > value
Definition: priority.hh:93
auto get_iterator(const std::bitset< N > &bs) -> bitset_iterator< N >
Definition: bitset.hh:48
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
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
typename internal::labelset_t_of_impl< internal::base_t< ValueSet > >::type labelset_t_of
Helper to retrieve the type of the labelset of a value set.
Definition: traits.hh:76
mutable_automaton< Context > make_mutable_automaton(const Context &ctx)
Definition: mutable_automaton.hh:911
std::shared_ptr< internal::mutable_automaton_impl< Context > > mutable_automaton
Definition: mutable_automaton.hh:45
typename internal::weightset_t_of_impl< internal::base_t< ValueSet > >::type weightset_t_of
Helper to retrieve the type of the weightset of a value set.
Definition: traits.hh:86
Main namespace of Awali.
Definition: ato.hh:22
unsigned state_t
Definition: types.hh:21
An output state is a list of weighted input states.
Definition: determinize.hxx:374
void kind_t
Definition: determinize.hxx:380
static bool less_than(state_t l, state_t r)
Definition: determinize.hxx:381
automaton_t aut_
Definition: determinize.hxx:386
stateset(const automaton_t &aut)
Definition: determinize.hxx:375
state_t value_t
Definition: determinize.hxx:379