Awali
Another Weighted Automata library
determinize.hxx
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 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  {
360  template <typename Aut>
362  {
363  static_assert(labelset_t_of<Aut>::is_free(),
364  "determinize: requires free labelset");
365 
366  public:
367  using automaton_t = Aut;
368 
372 
374  struct stateset
375  {
376  stateset(const automaton_t& aut)
377  : aut_(aut)
378  {}
379 
380  using value_t = state_t;
381  using kind_t = void;
382  static bool less_than(state_t l, state_t r)
383  {
384  return l < r;
385  }
386 
388  };
389 
392 
396  detweighted_algo_impl(const automaton_t& a, int lim=-1)
397  : input_(a)
398  , output_(make_mutable_automaton(a->context()))
399  , limit_(lim)
400  {}
401 
403  return (*this)([](state_name_t) {return true;});
404  }
405 
411  template<typename Pred>
413  {
414  state_name_t ss;
415  unknown_ = output_->null_state();
416  for (auto t : input_->initial_transitions())
417  ss.emplace(input_->dst_of(t), input_->weight_of(t));
418  output_->set_initial(state_(ss,0,pred(ss)));
419 
420  // label -> <destination, sum of weights>.
422  std::pair<state_name_t, weight_t>,
424  while (!todo_.empty())
425  {
426  ss = std::move(todo_.front().first);
427  unsigned depth = todo_.front().second;
428  todo_.pop();
429  auto src = map_[ss];
430  dests.clear();
431  for (const auto& p : ss)
432  {
433  auto s = p.first;
434  auto v = p.second;
435  for (auto t : input_->out(s))
436  {
437  auto l = input_->label_of(t);
438  auto dst = input_->dst_of(t);
439  auto w = ws_.mul(v, input_->weight_of(t));
440 
441  // For each letter, update destination state, and
442  // sum of weights.
443  if (dests.find(l)==dests.end())
444  dests.emplace(l, make_pair(ns_.zero(), ws_.zero()));
445  auto& d = dests[l];
446  ns_.add_here(d.first, dst, w);
447  d.second = ws_.add(d.second, w);
448  }
449  }
450  for (auto& d : dests)
451  output_->new_transition(src,
452  state_(d.second.first, depth+1, pred(d.second.first)),
453  d.first);
454  }
455  return output_;
456  }
457 
458  private:
461  state_t state_(const state_name_t& name, unsigned depth, bool true_state) {
462  // Benches show that the map_.emplace technique is slower, and
463  // then that operator[] is faster than emplace.
464  state_t res;
465  auto i = map_.find(name);
466  if (i == std::end(map_))
467  if(true_state && (limit_ <0 || depth <= (unsigned) limit_)) {
468  res = output_->add_state();
469  map_[name] = res;
470  for (const auto& p : name)
471  if (input_->is_final(p.first))
472  output_->add_final(res,
473  ws_.mul(p.second,
474  input_->get_final_weight(p.first)));
475 
476  todo_.push(std::make_pair(name,depth));
477  }
478  else {
479  if(unknown_ == output_->null_state()) {
480  unknown_ = output_->add_state();
481  for(auto l : output_->labelset()->genset())
482  output_->new_transition(unknown_, unknown_, l);
483  output_->set_state_name(unknown_,"...");
484  }
485  res = unknown_;
486  }
487  else
488  res = i->second;
489  return res;
490  };
491 
493  std::map<state_name_t, state_t, internal::less<state_nameset_t>> map_;
494 
496  automaton_t input_;
497 
499  automaton_t output_;
500 
502  weightset_t ws_ = *input_->weightset();
503 
505  state_nameset_t ns_ = {{stateset(input_), *input_->weightset()}};
506 
510  unsigned state_size_ = input_->max_state() + 1;
511 
513  using queue = std::queue<std::pair<state_name_t,unsigned>>;
514  queue todo_;
516  int limit_;
517  state_t unknown_;
518  };
519  }
520 
521 
522 }}//end of ns awali::stc
523 
524 #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:362
weight_t_of< automaton_t > weight_t
Definition: determinize.hxx:371
automaton_t operator()()
Definition: determinize.hxx:402
automaton_t operator()(Pred pred)
The determinization of weighted automaton the state is added to the result only if the predicate pred...
Definition: determinize.hxx:412
label_t_of< automaton_t > label_t
Definition: determinize.hxx:369
weightset_t_of< automaton_t > weightset_t
Definition: determinize.hxx:370
detweighted_algo_impl(const automaton_t &a, int lim=-1)
Build the weighted determinizer.
Definition: determinize.hxx:396
Aut automaton_t
Definition: determinize.hxx:367
typename state_nameset_t::value_t state_name_t
Definition: determinize.hxx:391
polynomialset< context< stateset, weightset_t > > state_nameset_t
Definition: determinize.hxx:390
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:35
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:915
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:375
void kind_t
Definition: determinize.hxx:381
static bool less_than(state_t l, state_t r)
Definition: determinize.hxx:382
automaton_t aut_
Definition: determinize.hxx:387
stateset(const automaton_t &aut)
Definition: determinize.hxx:376
state_t value_t
Definition: determinize.hxx:380