Vcsn  2.0
Be Rational
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
determinize.hh
Go to the documentation of this file.
1 #ifndef VCSN_ALGOS_DETERMINIZE_HH
2 # define VCSN_ALGOS_DETERMINIZE_HH
3 
4 # include <set>
5 # include <stack>
6 # include <string>
7 # include <type_traits>
8 # include <queue>
9 
10 # include <vcsn/algos/transpose.hh>
13 # include <vcsn/ctx/traits.hh>
14 # include <vcsn/dyn/automaton.hh> // dyn::make_automaton
15 # include <vcsn/dyn/fwd.hh>
17 # include <vcsn/misc/map.hh> // vcsn::has
18 # include <vcsn/misc/raise.hh> // b
19 # include <vcsn/misc/unordered_map.hh> // vcsn::has
20 # include <vcsn/weightset/fwd.hh> // b
21 
22 namespace vcsn
23 {
24 
25  /*----------------------.
26  | subset construction. |
27  `----------------------*/
28  namespace detail
29  {
35  template <typename Aut>
37  : public automaton_decorator<typename Aut::element_type::automaton_nocv_t>
38  {
39  static_assert(labelset_t_of<Aut>::is_free(),
40  "determinize: boolean: requires free labelset");
41  static_assert(std::is_same<weightset_t_of<Aut>, b>::value,
42  "determinize: boolean: requires Boolean weights");
43 
44  public:
45  using automaton_t = Aut;
46  using automaton_nocv_t = typename Aut::element_type::automaton_nocv_t;
50 
53 
56 
60  : super_t(a->context())
61  , input_(a)
63  {
64  // Pre.
65  state_name_t n;
66  n.resize(state_size_);
67  n.set(input_->pre());
68  map_[n] = super_t::pre();
69  todo_.push(n);
70 
71  // Final states.
72  for (auto t : input_->final_transitions())
73  finals_.set(input_->src_of(t));
74  }
75 
76  static std::string sname()
77  {
78  return "determinized_automaton<" + automaton_t::element_type::sname() + ">";
79  }
80 
81  std::string vname(bool full = true) const
82  {
83  return "determinized_automaton<" + input_->vname(full) + ">";
84  }
85 
89  {
90  // Benches show that the map_.emplace technique is slower, and
91  // then that operator[] is faster than emplace.
92  state_t res;
93  auto i = map_.find(ss);
94  if (i == std::end(map_))
95  {
96  res = this->new_state();
97  map_[ss] = res;
98 
99  if (ss.intersects(finals_))
100  this->set_final(res);
101 
102  todo_.push(ss);
103  }
104  else
105  res = i->second;
106  return res;
107  }
108 
110  void operator()()
111  {
112  std::map<label_t, state_name_t, vcsn::less<labelset_t_of<Aut>>> ml;
113  while (!todo_.empty())
114  {
115  auto ss = std::move(todo_.top());
116  state_t src = state(ss);
117  todo_.pop();
118 
119  ml.clear();
120  for (auto s = ss.find_first(); s != ss.npos;
121  s = ss.find_next(s))
122  {
123  // Cache the output transitions of state s.
124  auto i = successors_.find(s);
125  if (i == successors_.end())
126  {
127  i = successors_.emplace(s, label_map_t{}).first;
128  auto& j = i->second;
129  for (auto t : input_->out(s))
130  {
131  auto l = input_->label_of(t);
132  if (j.find(l) == j.end())
133  j[l].resize(state_size_);
134  j[l].set(input_->dst_of(t));
135  }
136  }
137 
138  // Store in ml the possible destination per label.
139  for (const auto& p : i->second)
140  {
141  auto j = ml.find(p.first);
142  if (j == ml.end())
143  ml[p.first] = p.second;
144  else
145  j->second |= p.second;
146  }
147  }
148 
149  // Outgoing transitions from the current (result) state.
150  for (const auto& e : ml)
151  this->new_transition(src, state(e.second), e.first);
152  }
153  }
154 
155  bool state_has_name(state_t s) const
156  {
157  return (s != super_t::pre()
158  && s != super_t::post()
159  && has(origins(), s));
160  }
161 
162  std::ostream&
163  print_state_name(state_t s, std::ostream& o,
164  const std::string& fmt = "text",
165  bool delimit = false) const
166  {
167  auto i = origins().find(s);
168  if (i == std::end(origins()))
169  this->print_state(s, o);
170  else
171  {
172  if (delimit)
173  o << '{';
174  const char* sep = "";
175  for (auto s: i->second)
176  {
177  o << sep;
178  input_->print_state_name(s, o, fmt, true);
179  sep = ", ";
180  }
181  if (delimit)
182  o << '}';
183  }
184  return o;
185  }
186 
188  using origins_t = std::map<state_t, std::set<state_t>>;
190 
191  const origins_t&
192  origins() const
193  {
194  if (origins_.empty())
195  for (const auto& p: map_)
196  {
197  std::set<state_t> from;
198  const auto& ss = p.first;
199  for (auto s = ss.find_first(); s != ss.npos;
200  s = ss.find_next(s))
201  from.emplace(s);
202  origins_.emplace(p.second, std::move(from));
203  }
204  return origins_;
205  }
206 
207  private:
209  using map_t = std::unordered_map<state_name_t, state_t>;
211 
214 
218  size_t state_size_ = input_->all_states().back() + 1;
219 
221  using stack = std::stack<state_name_t>;
223 
226 
228  using label_map_t = std::unordered_map<label_t, state_name_t,
231  using successors_t = std::map<state_t, label_map_t>;
233  };
234  }
235 
237  template <typename Aut>
239  = std::shared_ptr<detail::determinized_automaton_impl<Aut>>;
240 
241  template <typename Aut>
242  inline
243  auto
244  determinize(const Aut& a)
246  {
247  auto res = make_shared_ptr<determinized_automaton<Aut>>(a);
248  // Determinize.
249  res->operator()();
250  return res;
251  }
252 
253  template <typename Aut>
254  inline
255  auto
256  codeterminize(const Aut& a)
257  -> decltype(transpose(determinize(transpose(a))))
258  {
259  return transpose(determinize(transpose(a)));
260  }
261 
262  /*---------------------------.
263  | weighted determinization. |
264  `---------------------------*/
265  namespace detail
266  {
271  template <typename Aut>
273  : public automaton_decorator<typename Aut::element_type::automaton_nocv_t>
274  {
275  static_assert(labelset_t_of<Aut>::is_free(),
276  "determinize: weighted: requires free labelset");
277 
278  public:
279  using automaton_t = Aut;
280  using automaton_nocv_t = typename Aut::element_type::automaton_nocv_t;
282 
286 
289 
291  struct stateset
292  {
293  stateset(const automaton_t& aut)
294  : aut_(aut)
295  {}
296 
297  using value_t = state_t;
298  using kind_t = void;
299  static bool equals(state_t l, state_t r)
300  {
301  return l == r;
302  }
303 
304  static bool less_than(state_t l, state_t r)
305  {
306  return l < r;
307  }
308 
309  static size_t hash(state_t s)
310  {
311  return hash_value(s);
312  }
313 
314  std::ostream&
315  print(state_t s, std::ostream& out,
316  symbol format = symbol{"text"}) const
317  {
318  return aut_->print_state_name(s, out, format);
319  }
320 
322  };
323 
325  using state_name_t = typename state_nameset_t::value_t;
326 
330  : super_t(a->context())
331  , input_(a)
332  {
333  // Pre.
334  state_name_t n;
335  n.emplace(input_->pre(), ws_.one());
336  map_[n] = super_t::pre();
337  todo_.push(n);
338 
339  // Post.
340  n.clear();
341  n.emplace(input_->post(), ws_.one());
342  map_[n] = super_t::post();
343  }
344 
345  static std::string sname()
346  {
347  return "detweighted_automaton<" + automaton_t::element_type::sname() + ">";
348  }
349 
350  std::string vname(bool full = true) const
351  {
352  return "detweighted_automaton<" + input_->vname(full) + ">";
353  }
354 
357  void operator()()
358  {
359  // label -> <destination, sum of weights>.
362  while (!todo_.empty())
363  {
364  auto ss = std::move(todo_.front());
365  todo_.pop();
366  auto src = map_[ss];
367 
368  dests.clear();
369  for (const auto& p : ss)
370  {
371  auto s = p.first;
372  auto v = p.second;
373  for (auto t : input_->all_out(s))
374  {
375  auto l = input_->label_of(t);
376  auto dst = input_->dst_of(t);
377  auto w = ws_.mul(v, input_->weight_of(t));
378 
379  // For each letter, update destination state, and
380  // sum of weights.
381  if (!has(dests, l))
382  dests.emplace(l, ns_.zero());
383  auto& d = dests[l];
384  ns_.add_here(d, dst, w);
385  }
386  }
387 
388  for (auto& d : dests)
389  if (!ns_.is_zero(d.second))
390  {
391  weight_t w = ns_.normalize_here(d.second);
392  this->new_transition(src, state_(d.second),
393  d.first, w);
394  }
395  }
396  }
397 
398  bool state_has_name(state_t s) const
399  {
400  return (s != super_t::pre()
401  && s != super_t::post()
402  && has(origins(), s));
403  }
404 
405  std::ostream&
406  print_state_name(state_t ss, std::ostream& o,
407  const std::string& fmt = "text") const
408  {
409  auto i = origins().find(ss);
410  if (i == origins().end())
411  this->print_state(ss, o);
412  else
413  ns_.print(i->second, o, fmt, ", ");
414  return o;
415  }
416 
418  using origins_t = std::map<state_t, state_name_t>;
420  const origins_t&
421  origins() const
422  {
423  if (origins_.empty())
424  for (const auto& p: map_)
425  origins_.emplace(p.second, p.first);
426  return origins_;
427  }
428 
429  private:
433  {
434  // Benches show that the map_.emplace technique is slower, and
435  // then that operator[] is faster than emplace.
436  state_t res;
437  auto i = map_.find(name);
438  if (i == std::end(map_))
439  {
440  res = this->new_state();
441  map_[name] = res;
442  todo_.push(name);
443  }
444  else
445  res = i->second;
446  return res;
447  };
448 
450  using map_t = std::unordered_map<state_name_t, state_t,
454 
457 
459  weightset_t ws_ = *input_->weightset();
460 
463 
465  using queue = std::queue<state_name_t>;
467  };
468  }
469 
471  template <typename Aut>
473  = std::shared_ptr<detail::detweighted_automaton_impl<Aut>>;
474 
475  template <typename Aut>
476  inline
477  auto
478  determinize_weighted(const Aut& a)
480  {
481  auto res = make_shared_ptr<detweighted_automaton<Aut>>(a);
482  res->operator()();
483  return res;
484  }
485 
486  template <typename Aut>
487  inline
488  auto
489  codeterminize_weighted(const Aut& aut)
490  -> decltype(transpose(determinize_weighted(transpose(aut))))
491  {
493  }
494 
495  /*-------------------.
496  | dyn::determinize. |
497  `-------------------*/
498 
499  namespace dyn
500  {
501  namespace detail
502  {
503  template <typename Aut, typename Type>
504  using if_boolean_t
505  = typename std::enable_if<std::is_same<weightset_t_of<Aut>, b>::value,
506  Type>::type;
507 
508  template <typename Aut, typename Type>
509  using if_not_boolean_t
510  = typename std::enable_if<!std::is_same<weightset_t_of<Aut>, b>::value,
511  Type>::type;
512 
513 
515  template <typename Aut, typename String>
517  determinize(const automaton& aut, const std::string& algo)
518  {
519  const auto& a = aut->as<Aut>();
520  if (algo == "auto" || algo == "boolean")
521  return make_automaton(::vcsn::determinize(a));
522  else if (algo == "weighted")
524  else
525  raise("determinize: invalid algorithm: ", str_escape(algo));
526  }
527 
529  template <typename Aut, typename String>
530  if_not_boolean_t<Aut, automaton>
531  determinize(const automaton& aut, const std::string& algo)
532  {
533  const auto& a = aut->as<Aut>();
534  if (algo == "boolean")
535  raise("determinize: cannot apply Boolean determinization");
536  else if (algo == "auto" || algo == "weighted")
538  else
539  raise("determinize: invalid algorithm: ", str_escape(algo));
540  }
541 
543  (const automaton& aut, const std::string& algo) -> automaton);
544  }
545  }
546 
547 
548  /*---------------------.
549  | dyn::codeterminize. |
550  `---------------------*/
551 
553  namespace dyn
554  {
555  namespace detail
556  {
558  template <typename Aut, typename String>
559  if_boolean_t<Aut, automaton>
560  codeterminize(const automaton& aut, const std::string& algo)
561  {
562  const auto& a = aut->as<Aut>();
563  if (algo == "auto" || algo == "boolean")
564  return make_automaton(::vcsn::codeterminize(a));
565  else if (algo == "weighted")
567  else
568  raise("codeterminize: invalid algorithm: ", str_escape(algo));
569  }
570 
572  template <typename Aut, typename String>
573  if_not_boolean_t<Aut, automaton>
574  codeterminize(const automaton& aut, const std::string& algo)
575  {
576  const auto& a = aut->as<Aut>();
577  if (algo == "boolean")
578  raise("codeterminize: cannot apply Boolean determinization");
579  else if (algo == "auto" || algo == "weighted")
581  else
582  raise("codeterminize: invalid algorithm: ", str_escape(algo));
583  }
584 
586  (const automaton& aut, const std::string& algo) -> automaton);
587  }
588  }
589 
590 } // namespace vcsn
591 
592 #endif // !VCSN_ALGOS_DETERMINIZE_HH
if_boolean_t< Aut, automaton > determinize(const automaton &aut, const std::string &algo)
Boolean Bridge.
Definition: determinize.hh:517
Linear combination of labels: map labels to weights.
Definition: fwd.hh:32
std::shared_ptr< detail::determinized_automaton_impl< Aut >> determinized_automaton
A determinized automaton as a shared pointer.
Definition: determinize.hh:239
std::map< state_t, state_name_t > origins_t
A map from determinized states to sets of original states.
Definition: determinize.hh:418
auto codeterminize_weighted(const Aut &aut) -> decltype(transpose(determinize_weighted(transpose(aut))))
Definition: determinize.hh:489
std::unordered_map< state_name_t, state_t, vcsn::hash< state_nameset_t >, vcsn::equal_to< state_nameset_t >> map_t
Map from state name to state number.
Definition: determinize.hh:452
REGISTER_DECLARE(accessible,(const automaton &) -> automaton)
std::shared_ptr< detail::automaton_base > automaton
Definition: automaton.hh:71
typename state_nameset_t::value_t state_name_t
Definition: determinize.hh:325
auto codeterminize(const Aut &a) -> decltype(transpose(determinize(transpose(a))))
Definition: determinize.hh:256
label_t_of< automaton_t > label_t
Definition: determinize.hh:47
std::shared_ptr< detail::detweighted_automaton_impl< Aut >> detweighted_automaton
A determinized automaton as a shared pointer.
Definition: determinize.hh:473
const origins_t & origins() const
Definition: determinize.hh:192
weightset_t ws_
Its weightset.
Definition: determinize.hh:459
std::unordered_map< label_t, state_name_t, vcsn::hash< labelset_t >, vcsn::equal_to< labelset_t >> label_map_t
successors[SOURCE-STATE][LABEL] = DEST-STATESET.
Definition: determinize.hh:230
labelset_t_of< automaton_t > labelset_t
Definition: determinize.hh:48
label_t_of< automaton_t > label_t
Definition: determinize.hh:283
detweighted_automaton_impl(const automaton_t &a)
Build the weighted determinizer.
Definition: determinize.hh:329
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
Definition: traits.hh:34
weight_t_of< automaton_t > weight_t
Definition: determinize.hh:288
The weighted determinization of weighted automaton.
Definition: determinize.hh:272
if_boolean_t< Aut, automaton > codeterminize(const automaton &aut, const std::string &algo)
Boolean Bridge.
Definition: determinize.hh:560
size_t state_size_
We use state numbers as indexes, so we need to know the last state number.
Definition: determinize.hh:218
typename Aut::element_type::automaton_nocv_t automaton_nocv_t
Definition: determinize.hh:46
state_t_of< automaton_t > state_t
Result automaton state type.
Definition: determinize.hh:55
state_name_t finals_
Set of final states in the input automaton.
Definition: determinize.hh:225
automaton_t input_
Input automaton.
Definition: determinize.hh:456
polynomialset< context< stateset, weightset_t >> state_nameset_t
Definition: determinize.hh:324
boost::flyweight< std::string, boost::flyweights::no_tracking > symbol
An internalized string.
Definition: symbol.hh:24
std::string sname()
Definition: name.hh:31
typename std::enable_if< std::is_same< weightset_t_of< Aut >, b >::value, Type >::type if_boolean_t
Definition: determinize.hh:506
automaton make_automaton(const Aut &aut)
Build a dyn::automaton.
Definition: automaton.hh:77
variadic_mul_mixin< detail::b_impl > b
Definition: fwd.hh:38
dynamic_bitset state_name_t
The name: set of (input) states.
Definition: determinize.hh:52
std::ostream & str_escape(std::ostream &os, const std::string &str)
Output a string, escaping special characters.
Definition: escape.cc:43
typename Aut::element_type::automaton_nocv_t automaton_nocv_t
Definition: determinize.hh:280
std::map< state_t, label_map_t > successors_t
Definition: determinize.hh:231
automaton_t input_
Input automaton.
Definition: determinize.hh:213
auto new_state(Args &&...args) -> decltype(aut_-> new_state(std::forward< Args >(args)...))
std::size_t hash_value(const T &v)
Definition: hash.hh:61
labelset_t_of< automaton_t > labelset_t
Definition: determinize.hh:284
void operator()()
The determinization of weighted automaton with the idea based on Mohri's algorithm.
Definition: determinize.hh:357
std::string vname(bool full=true) const
Definition: determinize.hh:81
state_t state_(const state_name_t &name)
The state for set of states ss.
Definition: determinize.hh:432
Aggregate an automaton, and forward calls to it.
weightset_t_of< automaton_t > weightset_t
Definition: determinize.hh:285
std::ostream & print_state_name(state_t ss, std::ostream &o, const std::string &fmt="text") const
Definition: determinize.hh:406
The subset construction automaton from another.
Definition: determinize.hh:36
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:101
typename detail::label_t_of_impl< base_t< ValueSet >>::type label_t_of
Definition: traits.hh:33
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:38
state_nameset_t ns_
(Nameset) The polynomialset that stores weighted states.
Definition: determinize.hh:462
void operator()()
Determinize all accessible states.
Definition: determinize.hh:110
std::map< state_t, std::set< state_t >> origins_t
A map from determinized states to sets of original states.
Definition: determinize.hh:188
const origins_t & origins() const
Definition: determinize.hh:421
auto set_final(Args &&...args) -> decltype(aut_-> set_ final(std
An output state is a list of weighted input states.
Definition: determinize.hh:291
typename std::enable_if<!std::is_same< weightset_t_of< Aut >, b >::value, Type >::type if_not_boolean_t
Definition: determinize.hh:511
static bool equals(state_t l, state_t r)
Definition: determinize.hh:299
auto determinize(const Aut &a) -> determinized_automaton< Aut >
Definition: determinize.hh:244
state_t state(const state_name_t &ss)
The state for set of states ss.
Definition: determinize.hh:88
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:36
std::unordered_map< state_name_t, state_t > map_t
Set of input states -> output state.
Definition: determinize.hh:209
static bool less_than(state_t l, state_t r)
Definition: determinize.hh:304
typename detail::weight_t_of_impl< base_t< ValueSet >>::type weight_t_of
Definition: traits.hh:37
Aut transpose(const transpose_automaton< Aut > &aut)
Definition: transpose.hh:230
auto determinize_weighted(const Aut &a) -> detweighted_automaton< Aut >
Definition: determinize.hh:478
std::queue< state_name_t > queue
The sets of (input) states waiting to be processed.
Definition: determinize.hh:465
boost::dynamic_bitset<> dynamic_bitset
determinized_automaton_impl(const automaton_t &a)
Build the determinizer.
Definition: determinize.hh:59
static constexpr auto pre(Args &&...args) -> decltype(automaton_t::element_type::pre(std::forward< Args >(args)...))
std::ostream & print_state_name(state_t s, std::ostream &o, const std::string &fmt="text", bool delimit=false) const
Definition: determinize.hh:163
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: hash.hh:42
typename detail::state_t_of_impl< base_t< ValueSet >>::type state_t_of
Definition: traits.hh:35
state_t_of< automaton_t > state_t
Definition: determinize.hh:287
auto new_transition(Args &&...args) -> decltype(aut_-> new_transition(std::forward< Args >(args)...))
auto print_state(Args &&...args) const -> decltype(aut_-> print_state(std::forward< Args >(args)...))
std::stack< state_name_t > stack
The sets of (input) states waiting to be processed.
Definition: determinize.hh:221
variadic_mul_mixin< detail::r_impl > r
Definition: fwd.hh:42
bool has(const std::map< Key, Value, Compare, Alloc > &s, const Key &e)
Definition: map.hh:35
std::ostream & print(state_t s, std::ostream &out, symbol format=symbol{"text"}) const
Definition: determinize.hh:315
std::string vname(bool full=true) const
Definition: determinize.hh:350
static constexpr auto post(Args &&...args) -> decltype(automaton_t::element_type::post(std::forward< Args >(args)...))
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: hash.hh:26
auto out(Args &&...args) const -> decltype(aut_-> out(std::forward< Args >(args)...))