Vcsn  2.2
Be Rational
determinize.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <string>
4 
5 #include <vcsn/algos/tags.hh>
9 #include <vcsn/ctx/traits.hh>
10 #include <vcsn/dyn/automaton.hh> // dyn::make_automaton
11 #include <vcsn/dyn/fwd.hh>
12 #include <vcsn/misc/getargs.hh>
13 #include <vcsn/misc/raise.hh>
15 
16 namespace vcsn
17 {
18  /*----------------------.
19  | subset construction. |
20  `----------------------*/
21 
22  namespace detail
23  {
29  template <Automaton Aut, wet_kind_t Kind, bool Lazy = false>
31  : public automaton_decorator<polystate_automaton<Aut, Kind, Lazy>>
32  {
33  static_assert(labelset_t_of<Aut>::is_free(),
34  "determinize: requires free labelset");
35 
36  public:
37  using automaton_t = Aut;
38  constexpr static wet_kind_t kind = Kind;
39  using super_t
42 
49 
53 
55  using state_name_t = typename super_t::element_type::state_name_t;
56 
57  using super_t::aut_;
58  auto strip() const
59  {
60  return aut_->strip();
61  }
62  auto origins() const
63  {
64  return aut_->origins();
65  }
66 
70  : super_t{make_polystate_automaton<automaton_t, kind, Lazy>(a)}
71  {
72  // Final states.
73  for (auto t : final_transitions(aut_->input_))
74  aut_->ns_.new_weight(finals_,
75  aut_->input_->src_of(t),
76  aut_->input_->weight_of(t));
77  }
78 
79  static symbol sname()
80  {
81  static auto res = symbol{"determinized_automaton<"
83  + ", " + to_string(kind)
84  + ", " + (Lazy ? "true" : "false")
85  + '>'};
86  return res;
87  }
88 
89  std::ostream& print_set(std::ostream& o, format fmt = {}) const
90  {
91  o << "determinized_automaton<";
92  aut_->input_->print_set(o, fmt);
93  return o << ", " << to_string(kind)
94  << ", " << Lazy
95  << '>';
96  }
97 
99  void operator()()
100  {
101  while (!aut_->todo_.empty())
102  {
103  state_t src = aut_->state(aut_->todo_.front());
104  const auto& ss = aut_->state_name(aut_->todo_.front());
105  aut_->todo_.pop();
106  complete_(src, ss);
107  }
108  }
109 
111  auto all_out(state_t s) const
112  -> decltype(all_out(aut_, s))
113  {
114  if (Lazy && aut_->is_lazy(s))
115  complete_(s);
116  return aut_->all_out(s);
117  }
118 
119  private:
121  void complete_(state_t s) const
122  {
123  const auto& orig = origins();
124  const_cast<self_t&>(*this).complete_(s, orig.at(s));
125  }
126 
129  template <wet_kind_t K = kind>
130  auto complete_(state_t src, const state_name_t& ss)
131  -> std::enable_if_t<K == wet_kind_t::bitset>
132  {
133  static_assert(std::is_same<weight_t_of<Aut>, bool>::value,
134  "determinize: boolean: requires B or F2 weights");
135  if (Lazy)
136  aut_->set_lazy(src, false);
137  // label -> <destination, sum of weights>.
138  using dests_t
139  = std::map<label_t, state_name_t, vcsn::less<labelset_t>>;
140  auto dests = dests_t{};
141  for (const auto& p : ss)
142  {
143  auto s = label_of(p);
144  // Cache the output transitions of state s.
145  auto i = successors_.find(s);
146  if (i == successors_.end())
147  {
148  i = successors_.emplace(s, label_map_t{}).first;
149  auto& j = i->second;
150  for (auto t : out(aut_->input_, s))
151  {
152  auto l = aut_->input_->label_of(t);
153  auto dst = aut_->input_->dst_of(t);
154  if (j.find(l) == j.end())
155  j.emplace(l, aut_->zero());
156  aut_->ns_.new_weight(j[l], dst, aut_->ws_.one());
157  }
158  }
159 
160  // Store in dests the possible destinations per label.
161  for (const auto& p : i->second)
162  {
163  auto j = dests.find(p.first);
164  if (j == dests.end())
165  dests[p.first] = p.second;
166  else
167  aut_->ns_.add_here(j->second, p.second);
168  }
169  }
170 
171  // Outgoing transitions from the current (result) state.
172  for (auto& d : dests)
173  // Don't create transitions to the empty state.
174  if (!aut_->ns_.is_zero(d.second))
175  this->new_transition(src, aut_->state_(std::move(d.second)),
176  d.first);
177 
178  auto w = aut_->ns_.scalar_product(ss, finals_);
179  if (!aut_->ws_.is_zero(w))
180  this->set_final(src, w);
181  }
182 
184  template <wet_kind_t K = kind>
185  auto complete_(state_t src, const state_name_t& ss)
186  -> std::enable_if_t<K != wet_kind_t::bitset>
187  {
188  if (Lazy)
189  aut_->set_lazy(src, false);
190  // label -> <destination, sum of weights>.
191  using dests_t
192  = std::map<label_t, state_name_t, vcsn::less<labelset_t>>;
193  auto dests = dests_t{};
194  for (const auto& p : ss)
195  {
196  auto s = label_of(p);
197  auto v = weight_of(p);
198  for (auto t : out(aut_->input_, s))
199  {
200  auto l = aut_->input_->label_of(t);
201  auto dst = aut_->input_->dst_of(t);
202  auto w = aut_->ws_.mul(v, aut_->input_->weight_of(t));
203 
204  // For each letter, update destination state, and
205  // sum of weights.
206  if (!has(dests, l))
207  dests.emplace(l, aut_->zero());
208  aut_->ns_.add_here(dests[l], dst, w);
209  }
210  }
211 
212  // Outgoing transitions from the current (result) state.
213  for (auto& d : dests)
214  // Don't create transitions to the empty state.
215  if (!aut_->ns_.is_zero(d.second))
216  {
217  weight_t w = aut_->ns_.normalize_here(d.second);
218  this->new_transition(src, aut_->state_(std::move(d.second)),
219  d.first, w);
220  }
221 
222  auto w = aut_->ns_.scalar_product(ss, finals_);
223  if (!aut_->ws_.is_zero(w))
224  this->set_final(src, w);
225  }
226 
229 
234  using successors_t = std::map<state_t, label_map_t>;
236  };
237  }
238 
240  template <Automaton Aut, wet_kind_t Kind, bool Lazy = false>
242  = std::shared_ptr<detail::determinized_automaton_impl<Aut, Kind, Lazy>>;
243 
244  template <Automaton Aut, typename Tag, bool Lazy = false>
245  auto
246  determinize(const Aut& a, Tag = {}, bool_constant<Lazy> = {})
247  {
248  constexpr auto kind =
249  std::is_same<Tag, boolean_tag>::value
251  : detail::wet_kind<labelset_t_of<Aut>, weightset_t_of<Aut>>();
252  auto res = make_shared_ptr<determinized_automaton<Aut, kind, Lazy>>(a);
253  // Determinize.
254  if (!Lazy)
255  res->operator()();
256  return res;
257  }
258 
259  namespace detail
260  {
262  template <Automaton Aut>
263  using determinization_tag
264  = std::conditional_t<std::is_same<weight_t_of<Aut>, bool>::value,
265  boolean_tag,
267  }
268 
270  template <Automaton Aut, bool Lazy = false>
271  auto
272  determinize(const Aut& a, auto_tag = {}, bool_constant<Lazy> lazy = {})
273  {
274  return determinize(a, detail::determinization_tag<Aut>{}, lazy);
275  }
276 
277 
278 
279  /*-------------------.
280  | dyn::determinize. |
281  `-------------------*/
282 
283  namespace dyn
284  {
285  namespace detail
286  {
288  template <Automaton Aut, typename Type = void>
289  using enable_if_boolean_t
290  = std::enable_if_t<std::is_same<weight_t_of<Aut>, bool>::value, Type>;
291 
293  template <Automaton Aut, typename Type = void>
295  = std::enable_if_t<!std::is_same<weight_t_of<Aut>, bool>::value, Type>;
296 
297 
298  template <Automaton Aut, typename Tag, bool Lazy = false>
299  automaton determinize_tag_(const Aut& aut)
300  {
301  return make_automaton(::vcsn::determinize(aut, Tag{},
303  }
304 
306  template <Automaton Aut, typename String>
307  enable_if_boolean_t<Aut, automaton>
308  determinize_(const automaton& aut, const std::string& algo)
309  {
311  {
312  "determinization algorithm",
313  {
314  {"auto", determinize_tag_<Aut, auto_tag>},
315  {"boolean", determinize_tag_<Aut, boolean_tag>},
316  {"weighted", determinize_tag_<Aut, weighted_tag>},
317  {"lazy", "lazy,auto"},
318  {"lazy,auto", "lazy,weighted"},
319  {"lazy,weighted", determinize_tag_<Aut, weighted_tag, true>},
320  }
321  };
322  return map[algo](aut->as<Aut>());
323  }
324 
326  template <Automaton Aut, typename String>
327  enable_if_not_boolean_t<Aut, automaton>
328  determinize_(const automaton& aut, const std::string& algo)
329  {
331  {
332  "determinization algorithm",
333  {
334  {"auto", determinize_tag_<Aut, auto_tag>},
335  {"weighted", determinize_tag_<Aut, weighted_tag>},
336  {"lazy", "lazy,auto"},
337  {"lazy,auto", "lazy,weighted"},
338  {"lazy,weighted", determinize_tag_<Aut, weighted_tag, true>},
339  }
340  };
341  if (algo == "boolean")
342  raise("determinize: cannot apply Boolean"
343  " determinization to weighted automata");
344  return map[algo](aut->as<Aut>());
345  }
346 
348  template <Automaton Aut, typename String>
349  automaton
350  determinize(const automaton& aut, const std::string& algo)
351  {
352  return determinize_<Aut, String>(aut, algo);
353  }
354  }
355  }
356 
357 
358  /*----------------.
359  | codeterminize. |
360  `----------------*/
361 
362  template <Automaton Aut, typename Tag = auto_tag>
363  auto
364  codeterminize(const Aut& aut, Tag tag = {})
365  {
366  return transpose(determinize(transpose(aut), tag));
367  }
368 
369  /*---------------------.
370  | dyn::codeterminize. |
371  `---------------------*/
372 
373  // FIXME: code duplication with determinize.
374  namespace dyn
375  {
376  namespace detail
377  {
378  template <Automaton Aut, typename Tag>
380  {
381  return make_automaton(::vcsn::codeterminize(aut, Tag{}));
382  }
383 
385  template <Automaton Aut, typename String>
386  enable_if_boolean_t<Aut, automaton>
387  codeterminize_(const automaton& aut, const std::string& algo)
388  {
390  {
391  "codeterminization algorithm",
392  {
393  {"auto", codeterminize_tag_<Aut, auto_tag>},
394  {"boolean", codeterminize_tag_<Aut, boolean_tag>},
395  {"weighted", codeterminize_tag_<Aut, weighted_tag>},
396  }
397  };
398  return map[algo](aut->as<Aut>());
399  }
400 
402  template <Automaton Aut, typename String>
403  enable_if_not_boolean_t<Aut, automaton>
404  codeterminize_(const automaton& aut, const std::string& algo)
405  {
407  {
408  "codeterminization algorithm",
409  {
410  {"auto", codeterminize_tag_<Aut, auto_tag>},
411  {"weighted", codeterminize_tag_<Aut, weighted_tag>},
412  }
413  };
414  if (algo == "boolean")
415  raise("codeterminize: cannot apply Boolean"
416  " determinization to weighted automata");
417  return map[algo](aut->as<Aut>());
418  }
419 
421  template <Automaton Aut, typename String>
422  automaton
423  codeterminize(const automaton& aut, const std::string& algo)
424  {
425  return codeterminize_<Aut, String>(aut, algo);
426  }
427  }
428  }
429 } // namespace vcsn
void complete_(state_t s) const
Complete a state: find its outgoing transitions.
Definition: determinize.hh:121
std::integral_constant< bool, B > bool_constant
Definition: type_traits.hh:12
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:160
auto all_out(state_t s) const -> decltype(all_out(aut_, s))
All the outgoing transitions.
Definition: determinize.hh:111
automaton make_automaton(const Aut &aut)
Build a dyn::automaton.
Definition: automaton.hh:75
auto codeterminize(const Aut &aut, Tag tag={})
Definition: determinize.hh:364
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:59
auto weight_of(Args &&...args) const -> decltype(aut_-> weight_of(std::forward< Args >(args)...))
labelset_t_of< automaton_t > labelset_t
Definition: determinize.hh:45
Definition: a-star.hh:8
typename super_t::element_type::state_name_t state_name_t
The state name: set of (input) states.
Definition: determinize.hh:55
std::string to_string(direction d)
Conversion to string.
Definition: direction.cc:7
std::shared_ptr< detail::determinized_automaton_impl< Aut, Kind, Lazy >> determinized_automaton
A determinized automaton as a shared pointer.
Definition: determinize.hh:242
weightset_t_of< automaton_t > weightset_t
Definition: determinize.hh:47
std::enable_if_t<!std::is_same< weight_t_of< Aut >, bool >::value, Type > enable_if_not_boolean_t
Enable if Aut is not over Booleans.
Definition: determinize.hh:295
automaton_t aut_
The wrapped automaton, possibly const.
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
Definition: traits.hh:55
An input/output format for valuesets.
Definition: format.hh:11
std::ostream & print_set(std::ostream &o, format fmt={}) const
Definition: determinize.hh:89
std::map< state_t, label_map_t > successors_t
Definition: determinize.hh:234
typename detail::weight_t_of_impl< base_t< ValueSet >>::type weight_t_of
Definition: traits.hh:58
Aut transpose(const transpose_automaton< Aut > &aut)
Definition: transpose.hh:227
static constexpr wet_kind_t kind
Definition: determinize.hh:38
The subset construction automaton from another.
Definition: determinize.hh:30
auto determinize(const Aut &a, Tag={}, bool_constant< Lazy >={})
Definition: determinize.hh:246
typename detail::state_t_of_impl< base_t< ValueSet >>::type state_t_of
Definition: traits.hh:56
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:56
state_name_t finals_
Set of final states in the input automaton.
Definition: determinize.hh:228
A mapping from strings to Values.
Definition: getargs.hh:33
Tag to request the most appropriate version of an algorithm.
Definition: tags.hh:16
std::enable_if_t< std::is_same< weight_t_of< Aut >, bool >::value, Type > enable_if_boolean_t
Enable if Aut is over Booleans.
Definition: determinize.hh:290
label_t_of< automaton_t > label_t
Definition: determinize.hh:46
weight_t_of< automaton_t > weight_t
Definition: determinize.hh:48
Request the unordered_map implementation.
enable_if_not_boolean_t< Aut, automaton > determinize_(const automaton &aut, const std::string &algo)
Weighted Bridge.
Definition: determinize.hh:328
auto complete_(state_t src, const state_name_t &ss) -> std::enable_if_t< K==wet_kind_t::bitset >
Compute the outgoing transitions of this state.
Definition: determinize.hh:130
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:23
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:233
void operator()()
Determinize the automaton.
Definition: determinize.hh:99
Aggregate an automaton, and forward calls to it.
enable_if_not_boolean_t< Aut, automaton > codeterminize_(const automaton &aut, const std::string &algo)
Weighted Bridge.
Definition: determinize.hh:404
std::shared_ptr< detail::automaton_base > automaton
Definition: automaton.hh:69
std::conditional_t< std::is_same< weight_t_of< Aut >, bool >::value, boolean_tag, weighted_tag > determinization_tag
The best tag depending on the type of Aut.
Definition: determinize.hh:266
auto new_transition(Args &&...args) -> decltype(aut_-> new_transition(std::forward< Args >(args)...))
context_t_of< automaton_t > context_t
Labels and weights.
Definition: determinize.hh:44
wet_kind_t
Different implementations of wets.
Definition: wet.hh:197
symbol sname()
Definition: name.hh:67
typename detail::context_t_of_impl< base_t< ValueSet >>::type context_t_of
Definition: traits.hh:53
automaton determinize_tag_(const Aut &aut)
Definition: determinize.hh:299
auto set_final(Args &&...args) -> decltype(aut_-> set_ final(std
typename detail::label_t_of_impl< base_t< ValueSet >>::type label_t_of
Definition: traits.hh:54
ATTRIBUTE_PURE bool has(const boost::container::flat_set< Key, Compare, Allocator > &s, const Key &e)
Whether e is member of s.
Definition: setalpha.hh:25
auto complete_(state_t src, const state_name_t &ss) -> std::enable_if_t< K!=wet_kind_t::bitset >
Compute the outgoing transitions of this state.
Definition: determinize.hh:185
Request the bitset implementation (bool weights).
auto final_transitions(const Aut &aut) -> decltype(aut->all_in(aut->post()))
Indexes of transitions from (visible) final states.
Definition: automaton.hh:148
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: functional.hh:42
state_t_of< automaton_t > state_t
Definition: determinize.hh:52
automaton codeterminize_tag_(const Aut &aut)
Definition: determinize.hh:379
Request for the weighted version of an algorithm.
Definition: tags.hh:122
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: functional.hh:12
auto label_of(Args &&...args) const -> decltype(aut_-> label_of(std::forward< Args >(args)...))
State labelset.
Definition: fwd.hh:22
determinized_automaton_impl(const automaton_t &a)
Build the determinizer.
Definition: determinize.hh:69