Vcsn  2.1
Be Rational
is-synchronized.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <stack>
4 #include <vector>
5 #include <unordered_map>
6 
7 #include <vcsn/algos/fwd.hh>
8 #include <vcsn/ctx/context.hh>
11 #include <vcsn/dyn/automaton.hh> // dyn::make_automaton
12 #include <vcsn/misc/pair.hh> // hash
13 #include <vcsn/misc/tuple.hh> // index_sequence
14 #include <vcsn/misc/unordered_map.hh> // has
15 
16 namespace vcsn
17 {
18  namespace detail
19  {
20 
27  template <typename Aut>
28  class delay_automaton_impl
29  : public automaton_decorator<fresh_automaton_t_of<Aut>>
30  {
31  public:
32  using automaton_t = Aut;
39 
41  template <std::size_t... I>
43 
44  static constexpr size_t number_of_tapes = labelset_t_of<Aut>::size();
45 
47 
48  static constexpr index_t indices = {};
49 
51  using delay_t = std::array<size_t, number_of_tapes>;
52 
54  using state_name_t = std::pair<state_t, delay_t>;
55 
56 
57  template <size_t I>
58  using tape_labelset_t = typename labelset_t::template valueset_t<I>;
59 
61  : super_t(aut->context())
62  , aut_(aut)
63  {
64  map_[state_name_t(this->pre(), delay_t{})] = aut->pre();
65  map_[state_name_t(this->post(), delay_t{})] = aut->post();
66  }
67 
69  static symbol sname()
70  {
71  static symbol res("delay_automaton<"
73  return res;
74  }
75 
76  std::ostream& print_set(std::ostream& o, format fmt = {}) const
77  {
78  o << "delay_automaton<";
79  super_t::print_set(o, fmt);
80  return o << '>';
81  }
82 
84  using smap = std::unordered_map<state_name_t, state_t>;
85 
88  state_t state(const state_name_t& r)
89  {
90  // Benches show that the map_.emplace technique is slower, and
91  // then that operator[] is faster than emplace.
92  if (r.first == aut_->post())
93  return this->post();
94  state_t res;
95  auto i = map_.find(r);
96  if (i == std::end(map_))
97  {
98  res = super_t::new_state();
99  map_[r] = res;
100  todo_.push(r);
101  }
102  else
103  res = i->second;
104  return res;
105  }
106 
107  using super_t::new_transition;
108 
109  void
110  new_transition(const state_name_t& src, const state_name_t& dst,
111  const label_t& l, const weight_t& w)
112  {
113  super_t::new_transition(state(src), state(dst), l, w);
114  }
115 
116  bool state_has_name(state_t s) const
117  {
118  return has(origins(), s);
119  }
120 
121  std::ostream&
122  print_state_name(state_t s, std::ostream& o,
123  format fmt = {},
124  bool = false) const
125  {
126  auto ns = origins().at(s);
127  aut_->print_state_name(ns.first, o, fmt, true);
128  o << ":(";
129  auto a = ns.second;
130  for (int i = 0; i < a.size() - 1; i++)
131  o << a[i] << ',';
132  if (a.size())
133  o << a[a.size() - 1];
134  o << ')';
135  return o;
136  }
137 
138  delay_t delay_of(state_t s)
139  {
140  auto i = origins().find(s);
141  if (i == std::end(origins()))
142  return {};
143  else
144  return i->second.second;
145  }
146 
148  using origins_t = std::unordered_map<state_t, state_name_t>;
149  mutable origins_t origins_;
150 
151  const origins_t&
152  origins() const
153  {
154  if (origins_.empty())
155  for (const auto& p: map_)
156  origins_[p.second] = p.first;
157  return origins_;
158  }
159 
161  std::stack<state_name_t, std::vector<state_name_t>> todo_;
163  smap map_;
165  automaton_t aut_;
166  };
167 
168  template <typename Aut>
169  class synchronize_checker
170  {
171  static_assert(context_t_of<Aut>::is_lat,
172  "synchronize: automaton labelset must be a tupleset");
173 
174  public:
175  using automaton_t = Aut;
176  using out_automaton_t = delay_automaton<automaton_t>;
177  using state_t = state_t_of<automaton_t>;
178  using labelset_t = labelset_t_of<out_automaton_t>;
179  using label_t = typename labelset_t::value_t;
180  using delay_t = typename out_automaton_t::element_type::delay_t;
181  using state_name_t = typename out_automaton_t::element_type::state_name_t;
182 
183  template <size_t I>
184  using tape_labelset_t = typename labelset_t::template valueset_t<I>;
185 
187  template <std::size_t... I>
188  using seq = vcsn::detail::index_sequence<I...>;
189 
190 
191  synchronize_checker(const automaton_t& aut)
192  : in_aut_(aut), out_aut_(make_shared_ptr<out_automaton_t>(aut))
193  {}
194 
202  bool is_synchronized()
203  {
204  // tag the states with the delays
205  value_automaton();
206  for (auto s : out_aut_->states())
207  {
208  delay_t d = out_aut_->delay_of(s);
209  if (d != delay_t{})
210  for (auto tr : out_aut_->out(s))
211  {
212  if (out_aut_->labelset()->is_one(out_aut_->label_of(tr)))
213  continue;
214  auto dst = out_aut_->dst_of(tr);
215  if (out_aut_->post() == dst)
216  continue;
217  delay_t dst_d = out_aut_->delay_of(dst);
218  for (size_t i = 0; i < out_aut_->number_of_tapes; i++) {
219  if (d[i] && dst_d[i] <= d[i])
220  return false;
221  }
222  }
223  }
224  return true;
225  }
226 
227  out_automaton_t
228  make_delay_automaton()
229  {
230  value_automaton();
231  return out_aut_;
232  }
233 
234  private:
235 
236  /*
237  * Compute the automaton with states tagged with their delays.
238  *
239  * If split, create the artificial states required for synchronizing.
240  */
241  void value_automaton()
242  {
243  out_aut_->todo_.emplace(in_aut_->pre(), delay_t{});
244 
245  while (!out_aut_->todo_.empty())
246  {
247  auto val_state = std::move(out_aut_->todo_.top());
248  auto st = val_state.first;
249  delay_t delay = val_state.second;
250  out_aut_->todo_.pop();
251  for (auto t : in_aut_->all_out(st))
252  {
253  auto l = in_aut_->label_of(t);
254  auto dst = in_aut_->dst_of(t);
255  delay_t d = add_delay_(delay, l, out_aut_->indices);
256  state_name_t new_state(dst, d);
257  out_aut_->new_transition(val_state,
258  new_state,
259  l,
260  in_aut_->weight_of(t));
261  }
262  }
263  }
264 
266  template <size_t... I>
267  delay_t
268  add_delay_(delay_t d, const label_t& l, seq<I...>) const
269  {
270  delay_t del
271  = {(std::get<I>(d) + tape_labelset_t<I>::size(std::get<I>(l)))...};
272  size_t min = *std::min_element(begin(del), end(del));
273  return {(std::get<I>(del) - min)...};
274  }
275 
276  automaton_t in_aut_;
277  out_automaton_t out_aut_;
278  };
279 
280  template <typename Aut>
281  bool is_synchronized(const Aut& aut)
282  {
283  synchronize_checker<Aut> s(aut);
284  return s.is_synchronized();
285  }
286 
287  template <typename Aut>
288  delay_automaton<Aut>
289  make_delay_automaton(const Aut& aut)
290  {
291  synchronize_checker<Aut> s(aut);
292  return s.make_delay_automaton();
293  }
294 
295  }
296 
297  /*------------------.
298  | is_synchronized. |
299  `------------------*/
300 
305  template <typename Aut>
306  bool
307  is_synchronized(const Aut& aut)
308  {
309  return detail::is_synchronized(aut);
310  }
311 
312  namespace dyn
313  {
314  namespace detail
315  {
317  template <typename Aut>
318  bool is_synchronized(const automaton& aut)
319  {
320  return vcsn::is_synchronized(aut->as<Aut>());
321  }
322  }
323  }
324 
325  /*------------------.
326  | delay_automaton. |
327  `------------------*/
328 
333  template <typename Aut>
334  auto
335  make_delay_automaton(const Aut& aut)
336  -> decltype(detail::make_delay_automaton(aut))
337  {
338  return detail::make_delay_automaton(aut);
339  }
340 
341  namespace dyn
342  {
343  namespace detail
344  {
346  template <typename Aut>
347  automaton delay_automaton(const automaton& aut)
348  {
349  return make_automaton(vcsn::make_delay_automaton(aut->as<Aut>()));
350  }
351  }
352  }
353 }
typename detail::label_t_of_impl< base_t< ValueSet >>::type label_t_of
Definition: traits.hh:46
static constexpr auto pre(Args &&...args) -> decltype(element_type::pre(std::forward< Args >(args)...))
std::pair< state_t, delay_t > state_name_t
State + delay.
static constexpr auto post(Args &&...args) -> decltype(element_type::post(std::forward< Args >(args)...))
labelset_t_of< super_t > labelset_t
static symbol sname()
Static name.
typename detail::state_t_of_impl< base_t< ValueSet >>::type state_t_of
Definition: traits.hh:48
typename detail::context_t_of_impl< base_t< ValueSet >>::type context_t_of
Definition: traits.hh:45
context_t_of< super_t > context_t
Aggregate an automaton, and forward calls to it.
static constexpr index_t indices
auto print_set(Args &&...args) const -> decltype(aut_-> print_set(std::forward< Args >(args)...))
std::array< size_t, number_of_tapes > delay_t
The delay associated with each state.
An input/output format.
Definition: format.hh:11
size_t size(const ExpSet &rs, const typename ExpSet::value_t &r)
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
Definition: traits.hh:47
std::ostream & print_set(std::ostream &o, format fmt={}) const
automaton_t aut_
The original automaton.
symbol sname()
Definition: name.hh:67
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:23
static constexpr size_t number_of_tapes
typename labelset_t::template valueset_t< I > tape_labelset_t
delay_automaton_impl(const automaton_t &aut)
smap map_
delayed_state -> state.
typename detail::weight_t_of_impl< base_t< ValueSet >>::type weight_t_of
Definition: traits.hh:50