Vcsn  2.6
Be Rational
compose.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <vcsn/algos/focus.hh>
4 #include <vcsn/algos/insplit.hh>
8 #include <vcsn/ctx/context.hh>
9 #include <vcsn/dyn/automaton.hh> // dyn::make_automaton
11 #include <vcsn/misc/raise.hh>
12 #include <vcsn/misc/tuple.hh> // make_index_sequence, cross_tuple
13 #include <vcsn/misc/zip-maps.hh>
15 
16 namespace vcsn
17 {
18  namespace detail
19  {
24 #define DEFINE(Type) \
25  template <Automaton Aut> \
26  struct Type ## _of_impl \
27  { \
28  using type = typename Aut::element_type::Type; \
29  }; \
30  \
31  template <Automaton Aut> \
32  struct Type ## _of_impl<insplit_automaton<Aut>> \
33  : Type ## _of_impl<Aut> \
34  {}; \
35  \
36  template <Automaton Aut> \
37  using Type ## _of \
38  = typename Type ## _of_impl<Aut>::type
39 
40  DEFINE(res_labelset_t);
41  DEFINE(res_label_t);
42  DEFINE(full_context_t);
43 #undef DEFINE
44 
46  template <Automaton Lhs, Automaton Rhs>
48  {
49  using clhs_t = Lhs;
50  using crhs_t = Rhs;
51  // clhs_t and crhs_t are permutation automata, yet we need to
52  // read the res_label_t from their wrapped automaton type.
55  using hidden_l_label_t = typename hidden_l_labelset_t::value_t;
56  using hidden_r_label_t = typename hidden_r_labelset_t::value_t;
57 
58 
64 
65  using res_label_t = typename labelset_t::value_t;
67 
70  };
71 
72 
73  /*------------------------------------------.
74  | compose_automaton<automaton, automaton>. |
75  `------------------------------------------*/
76 
78  template <bool Lazy, Automaton Lhs, Automaton Rhs>
80  : public lazy_tuple_automaton<compose_automaton_impl<Lazy, Lhs, Rhs>,
81  true,
82  Lazy,
83  typename composed_type<Lhs, Rhs>::out_t,
84  Lhs, Rhs>
85  {
86  static_assert(full_context_t_of<Lhs>::is_lat,
87  "compose: lhs labelset must be a tupleset");
88  static_assert(full_context_t_of<Rhs>::is_lat,
89  "compose: rhs labelset must be a tupleset");
90 
91  static_assert(std::is_same<labelset_t_of<Lhs>,
92  labelset_t_of<Rhs>>::value,
93  "compose: common tape must be of same type");
94 
96  template <std::size_t... I>
98 
99  public:
100 
102 
108 
109 
113 
116 
117  using out_t = typename type_helper_t::out_t;
120  using state_t = typename super_t::state_t;
123 
125  using automata_t = std::tuple<Lhs, Rhs>;
126 
128  template <size_t I>
130 
132  enum { Rank = 2 };
133 
134  using super_t::aut_;
135 
136  static symbol sname()
137  {
138  static symbol res(std::string{"compose_automaton<"}
139  + (Lazy ? "true" : "false") + ", "
140  + Lhs::element_type::sname() + ", "
141  + Rhs::element_type::sname() + ">");
142  return res;
143  }
144 
145  std::ostream& print_set(std::ostream& o, format fmt = {}) const
146  {
147  o << "compose_automaton<";
148  std::get<0>(aut_->auts_)->print_set(o, fmt) << ", ";
149  return std::get<1>(aut_->auts_)->print_set(o, fmt) << ">";
150  }
151 
152  compose_automaton_impl(const Lhs& lhs, const Rhs& rhs)
153  : super_t{make_mutable_automaton(make_context_(lhs, rhs)), lhs, rhs}
154  {}
155 
157  void compose()
158  {
159  initialize_compose();
160 
161  if (!Lazy)
162  while (!aut_->todo_.empty())
163  {
164  const auto& p = aut_->todo_.front();
165  add_compose_transitions(std::get<1>(p), std::get<0>(p));
166  aut_->todo_.pop_front();
167  }
168  }
169 
171  void add_transitions(const state_t src,
172  const state_name_t& psrc)
173  {
174  add_compose_transitions(src, psrc);
175  }
176 
177  using label_t = typename labelset_t::value_t;
178  using weight_t = typename weightset_t::value_t;
179 
180  private:
183  template <Automaton A>
184  static auto real_aut(const A& aut)
185  {
186  return aut;
187  }
188 
190  template <Automaton A>
191  static auto real_aut(const insplit_automaton<A>& aut)
192  {
193  return aut->strip();
194  }
195 
198  template <Automaton A>
199  using transition_map_t
201 
203  const hidden_r_labelset_t& rl)
204  {
205  constexpr auto lsize = hidden_l_labelset_t::size();
206  constexpr auto rsize = hidden_r_labelset_t::size();
207  return make_labelset_(ll, make_index_sequence<lsize>{},
209  }
210 
211  template <std::size_t... I1, std::size_t... I2>
213  seq<I1...>,
214  const hidden_r_labelset_t& rl,
215  seq<I2...>)
216  {
217  return labelset_t{std::get<I1>(ll.sets())...,
218  std::get<I2>(rl.sets())...};
219  }
220 
221  static context_t
222  make_context_(const Lhs& lhs, const Rhs& rhs)
223  {
224  return {make_labelset_(lhs->res_labelset(),
225  real_aut(rhs)->res_labelset()),
226  join(*lhs->weightset(), *rhs->weightset())};
227  }
228 
232  {
233  aut_->todo_.emplace_back(aut_->pre_(), aut_->pre());
234  }
235 
237  const hidden_r_label_t& rl) const
238  {
239  return std::tuple_cat(ll, rl);
240  }
241 
242  template <Automaton Aut>
243  std::enable_if_t<labelset_t_of<Aut>::has_one(),
245  get_hidden_one(const Aut& aut) const
246  {
247  return aut->hidden_one();
248  }
249 
250  template <Automaton Aut>
251  std::enable_if_t<labelset_t_of<Aut>::has_one(),
254  {
255  return real_aut(aut)->hidden_one();
256  }
257 
258  template <Automaton Aut>
259  ATTRIBUTE_NORETURN
260  std::enable_if_t<!labelset_t_of<Aut>::has_one(),
262  get_hidden_one(const Aut&) const
263  {
264  raise("should not get here");
265  }
266 
267  using super_t::transition_maps_;
273  const state_name_t& psrc)
274  {
275  const auto& lhs = std::get<0>(aut_->auts_);
276  const auto& rhs = std::get<1>(aut_->auts_);
277 
278  // Outgoing transition cache.
279  const auto& ltm = std::get<0>(transition_maps_)[std::get<0>(psrc)];
280  const auto& rtm = std::get<1>(transition_maps_)[std::get<1>(psrc)];
281 
282  add_one_transitions_<0>(src, psrc);
283  add_one_transitions_<1>(src, psrc);
284 
285  // In order to avoid having to call add_transition each time, we cache
286  // the transitions we add using a polynomial. We conserve a polynomial
287  // for each successor of src.
288  using polynomialset_t
290  using polynomial_t = typename polynomialset_t::value_t;
291  const auto ps = polynomialset_t(aut_->context());
292  auto poly_maps = std::map<state_t, polynomial_t>();
293 
294  for (const auto& t: zip_maps(ltm, rtm))
295  // The type of the common label is that of the visible tape
296  // of either automata.
297  if (!lhs->labelset()->is_one(t.first))
298  // These may not be new transitions: as the automata are focus,
299  // there might be two transitions with the same destination and
300  // label, with only the hidden part that changes.
302  ([&] (const typename transition_map_t<Lhs>::transition& lts,
303  const typename transition_map_t<Rhs>::transition& rts)
304  {
305  // Cache the transitions.
306  ps.add_here(poly_maps[this->state(lts.dst, rts.dst)],
307  join_label(lhs->hidden_label_of(lts.transition),
308  real_aut(rhs)->hidden_label_of(rts.transition)),
309  this->weightset()->mul(lts.weight(), rts.weight()));
310  },
311  t.second);
312 
313  // For each successor, add a transition for each monomial of the
314  // corresponding polynomial.
315  for (const auto& elt: poly_maps)
316  for (const auto& m: elt.second)
317  this->new_transition(src, elt.first, m.first, m.second);
318  }
319 
320 
321  template <std::size_t I>
322  void add_one_transitions_(const state_t src, const state_name_t& psrc)
323  {
324  // The first condition prevents the creation of redundant
325  // paths that would lead to incorrect valuations (in the
326  // weighted case), while the second is purely an optimization,
327  // avoiding the creation of non-coaccessible states.
328  if (are_proper_in(psrc, make_index_range<I + 1, Rank>{})
329  && have_proper_out(psrc, make_index_range<0, I>{}))
330  {
331  const auto& ls = *std::get<I>(aut_->auts_)->labelset();
332  const auto& tmap = std::get<I>(transition_maps_)[std::get<I>(psrc)];
333  if (!tmap.empty() && ls.is_one(tmap.begin()->first))
334  for (const auto& t: tmap.begin()->second)
335  {
336  // Tuple of destination states.
337  auto pdst =
338  static_if<I == 0>
339  ([dst=t.dst, &psrc]{
340  return std::make_tuple(dst, std::get<1>(psrc));
341  },
342  [dst=t.dst, &psrc]{
343  return std::make_tuple(std::get<0>(psrc), dst);
344  })();
345  // Label.
346  auto lbl =
347  static_if<I == 0>
348  ([this, t=t.transition](const auto& lhs, const auto& rhs)
349  {
350  return join_label(lhs->hidden_label_of(t),
351  get_hidden_one(real_aut(rhs)));
352  },
353  [this, t=t.transition](const auto& lhs, const auto& rhs)
354  {
355  return join_label(get_hidden_one(lhs),
356  real_aut(rhs)->hidden_label_of(t));
357  })
358  (std::get<0>(aut_->auts_), std::get<1>(aut_->auts_));
359  this->new_transition(src, this->state(pdst), lbl, t.weight());
360  }
361  }
362  }
363 
364  template <Automaton Aut>
365  std::enable_if_t<labelset_t_of<Aut>::has_one(), bool>
366  is_one(const Aut& aut, transition_t_of<Aut> tr) const
367  {
368  return aut->labelset()->is_one(aut->label_of(tr));
369  }
370 
371  template <Automaton Aut>
372  constexpr
373  std::enable_if_t<!labelset_t_of<Aut>::has_one(), bool>
374  is_one(const Aut&, transition_t_of<Aut>) const
375  {
376  return false;
377  }
378 
381  template <std::size_t... I>
382  bool are_proper_in(const state_name_t& psrc, seq<I...>) const
383  {
384  return all(is_proper_in<I>(psrc)...);
385  }
386 
388  template <size_t I>
389  constexpr auto
391  -> std::enable_if_t<!labelset_t_of<input_automaton_t<I>>::has_one(),
392  bool>
393  {
394  return true;
395  }
396 
401  template <size_t I>
402  auto
403  is_proper_in(const state_name_t& sn) const
404  -> std::enable_if_t<labelset_t_of<input_automaton_t<I>>::has_one(),
405  bool>
406  {
407  // Amusingly enough, it is faster to check the incoming
408  // transitions rather than recovering the decoration of the
409  // insplit state, which tells whether the state is proper-in.
410  const auto& aut = std::get<I>(aut_->auts_);
411  auto s = std::get<I>(sn);
412  auto rin = all_in(aut, s);
413  auto rtr = rin.begin();
414  // Insplit state, so checking the first transition suffices.
415  // There can be no incoming transitions in the case of pre.
416  return rtr == rin.end() || !is_one(aut, *rtr);
417  }
418 
421  template <std::size_t... I>
423  {
424  return all(has_proper_out<I>(psrc)...);
425  }
426 
432  template <size_t I>
433  bool
435  {
436  const auto& tmap = std::get<I>(transition_maps_)[std::get<I>(psrc)];
437  auto s = tmap.size();
438  if (s == 0)
439  return false;
440  else if (2 <= s)
441  return true;
442  else
443  return !std::get<I>(aut_->auts_)->labelset()->is_one(tmap.begin()->first);
444  }
445  };
446  }
447 
449  template <bool Lazy, Automaton Lhs, Automaton Rhs>
450  using compose_automaton
451  = std::shared_ptr<detail::compose_automaton_impl<Lazy, Lhs, Rhs>>;
452 
453  template <bool Lazy, std::size_t OutTape, std::size_t InTape,
454  Automaton Lhs, Automaton Rhs>
455  auto
456  make_compose_automaton(const Lhs& lhs, const Rhs& rhs)
457  {
458  auto l = focus<OutTape>(lhs);
459  auto r = insplit(focus<InTape>(rhs), true);
460  using res_t = compose_automaton<Lazy,
462  decltype(r)>;
463  return make_shared_ptr<res_t>(l, r);
464  }
465 
466  /*--------------------------------.
467  | compose(automaton, automaton). |
468  `--------------------------------*/
469 
471  template <Automaton Lhs, Automaton Rhs,
472  std::size_t OutTape = 1, std::size_t InTape = 0>
473  auto
474  compose(const Lhs& lhs, const Rhs& rhs)
475  {
476  auto res = make_compose_automaton<false, OutTape, InTape>(lhs, rhs);
477  res->compose();
478  return res->strip();
479  }
480 
482  template <typename Lhs, typename Rhs,
483  std::size_t OutTape = 1, std::size_t InTape = 0>
484  auto
485  compose_lazy(const Lhs& lhs, const Rhs& rhs)
486  {
487  auto res = make_compose_automaton<true, OutTape, InTape>(lhs, rhs);
488  res->compose();
489  return res;
490  }
491 
492  namespace dyn
493  {
494  namespace detail
495  {
497  template <Automaton Lhs, Automaton Rhs, typename Bool>
498  automaton
499  compose(const automaton& lhs, const automaton& rhs, bool lazy)
500  {
501  auto& l = lhs->as<Lhs>();
502  auto& r = rhs->as<Rhs>();
503  if (lazy)
505  else
507  }
508  }
509  }
510 }
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
zipped_maps< Dereference, Maps... > zip_maps(Maps &&... maps)
Definition: zip-maps.hh:250
typename type_helper_t::hidden_r_labelset_t hidden_r_labelset_t
Definition: compose.hh:105
void compose()
The (accessible part of the) composition of lhs_ and rhs_.
Definition: compose.hh:157
A static range.
Definition: tuple.hh:103
std::string type(const automaton &a)
The implementation type of a.
Definition: others.cc:238
typename weightset_t::value_t weight_t
Definition: compose.hh:178
typename type_helper_t::hidden_r_label_t hidden_r_label_t
Definition: compose.hh:107
auto make_compose_automaton(const Lhs &lhs, const Rhs &rhs)
Definition: compose.hh:456
typename hidden_l_labelset_t::value_t hidden_l_label_t
Definition: compose.hh:55
typename tuple_automaton_impl::state_t state_t
std::shared_ptr< detail::mutable_automaton_impl< Context > > mutable_automaton
Definition: fwd.hh:25
typename type_helper_t::labelset_t labelset_t
The type of context of the result.
Definition: compose.hh:111
Decorator implementing the laziness for an algorithm.
typename type_helper_t::hidden_l_label_t hidden_l_label_t
Definition: compose.hh:106
typename concat_tupleset< hidden_l_labelset_t, hidden_r_labelset_t >::type labelset_t
The type of context of the result.
Definition: compose.hh:61
typename res_labelset_t_of_impl< Aut >::type res_labelset_t_of
Definition: compose.hh:40
auto join(const ValueSet &vs) -> ValueSet
The join of a single valueset.
Definition: join.hh:44
bool have_proper_out(const state_name_t &psrc, seq< I... >)
Whether all the tapes in the sequence have proper outgoing transitions (but possibly spontaneous too)...
Definition: compose.hh:422
bool all(Bool &&... values)
Whether all the values evaluate as true.
Definition: tuple.hh:492
std::tuple< Lhs, Rhs > automata_t
The type of input automata.
Definition: compose.hh:125
#define DEFINE(Type)
Get a type from a possibly insplit automaton.
Definition: compose.hh:24
typename tuple_automaton_impl::state_name_t state_name_t
Build the (accessible part of the) composition.
Definition: compose.hh:79
void add_compose_transitions(const state_t src, const state_name_t &psrc)
Add transitions to the given result automaton, starting from the given result input state...
Definition: compose.hh:272
std::shared_ptr< insplit_automaton_impl< Aut > > insplit_automaton
An insplit automaton as a shared pointer.
Definition: insplit.hh:232
Cache the outgoing transitions of an automaton as efficient maps label -> vector<(weight, dst)>.
std::shared_ptr< detail::focus_automaton_impl< Tape, Aut > > focus_automaton
A focus automaton as a shared pointer.
Definition: fwd.hh:42
auto insplit(Aut aut, bool lazy=false) -> std::enable_if_t< labelset_t_of< Aut >::has_one(), decltype(make_insplit_automaton(aut))>
Insplit an automaton with possible spontaneous transitions.
Definition: insplit.hh:247
auto compose_lazy(const Lhs &lhs, const Rhs &rhs)
Build the (accessible part of the) lazy composition.
Definition: compose.hh:485
typename detail::labelset_t_of_impl< base_t< ValueSet > >::type labelset_t_of
Definition: traits.hh:63
compose_automaton_impl(const Lhs &lhs, const Rhs &rhs)
Definition: compose.hh:152
typename hidden_r_labelset_t::value_t hidden_r_label_t
Definition: compose.hh:56
symbol sname()
Definition: name.hh:65
automaton compose(const automaton &lhs, const automaton &rhs, bool lazy)
Bridge.
Definition: compose.hh:499
return res
Definition: multiply.hh:399
vs print_set(o)
res_labelset_t_of< clhs_t > hidden_l_labelset_t
Definition: compose.hh:53
An input/output format for valuesets.
Definition: format.hh:13
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
typename type_helper_t::res_label_t res_label_t
Definition: compose.hh:114
std::ostream & print_set(std::ostream &o, format fmt={}) const
Definition: compose.hh:145
res_label_t join_label(const hidden_l_label_t &ll, const hidden_r_label_t &rl) const
Definition: compose.hh:236
A dyn automaton.
Definition: automaton.hh:17
mutable_automaton< context_t > out_t
The automaton type for the composition of Lhs with Rhs.
Definition: compose.hh:69
void add_transitions(const state_t src, const state_name_t &psrc)
Callback for complete_ when lazy.
Definition: compose.hh:171
size_t size(const ExpSet &rs, const typename ExpSet::value_t &r)
ATTRIBUTE_NORETURN std::enable_if_t<!labelset_t_of< Aut >::has_one(), res_label_t_of< Aut > > get_hidden_one(const Aut &) const
Definition: compose.hh:262
typename type_helper_t::hidden_l_labelset_t hidden_l_labelset_t
Definition: compose.hh:104
Build the static sequence of size_t [0, N[.
Definition: tuple.hh:56
void add_one_transitions_(const state_t src, const state_name_t &psrc)
Definition: compose.hh:322
static context_t make_context_(const Lhs &lhs, const Rhs &rhs)
Definition: compose.hh:222
A static list of size_t.
Definition: tuple.hh:32
static auto real_aut(const insplit_automaton< A > &aut)
Get the focus automaton from an insplit automaton.
Definition: compose.hh:191
static labelset_t make_labelset_(const hidden_l_labelset_t &ll, seq< I1... >, const hidden_r_labelset_t &rl, seq< I2... >)
Definition: compose.hh:212
Build the (accessible part of the) composition.
Definition: compose.hh:47
void initialize_compose()
Fill the worklist with the initial source-state pairs, as needed for the composition algorithm...
Definition: compose.hh:231
bool are_proper_in(const state_name_t &psrc, seq< I... >) const
Whether no tapes in the sequence have spontaneous incoming transitions.
Definition: compose.hh:382
std::shared_ptr< detail::compose_automaton_impl< Lazy, Lhs, Rhs > > compose_automaton
A compose automaton as a shared pointer.
Definition: compose.hh:451
decltype(join(std::declval< ValueSets >()...)) join_t
The type of the join of the ValueSets.
Definition: join.hh:78
typename detail::weightset_t_of_impl< base_t< ValueSet > >::type weightset_t_of
Definition: traits.hh:67
#define Automaton
Definition: automaton.hh:23
typename type_helper_t::context_t context_t
Definition: compose.hh:115
constexpr auto is_proper_in(const state_name_t &) const -> std::enable_if_t<!labelset_t_of< input_automaton_t< I >>::has_one(), bool >
Whether the state has only proper incoming transitions.
Definition: compose.hh:390
std::enable_if_t< labelset_t_of< Aut >::has_one(), res_label_t_of< Aut > > get_hidden_one(const Aut &aut) const
Definition: compose.hh:245
mutable_automaton< Context > make_mutable_automaton(const Context &ctx)
auto is_proper_in(const state_name_t &sn) const -> std::enable_if_t< labelset_t_of< input_automaton_t< I >>::has_one(), bool >
Whether the state has only proper incoming transitions.
Definition: compose.hh:403
typename labelset_t::value_t res_label_t
Definition: compose.hh:65
Definition: a-star.hh:8
Outgoing signature: weight, destination.
bool has_proper_out(const state_name_t &psrc)
Whether the Ith state of psrc in the Ith input automaton has proper outgoing transitions (but possibl...
Definition: compose.hh:434
typename type_helper_t::out_t out_t
Definition: compose.hh:117
typename super_t::state_name_t state_name_t
Tuple of states of input automata.
Definition: compose.hh:122
void cross_tuple(Fun f, const std::tuple< Ts... > &ts)
Definition: tuple.hh:347
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:21
join_t< weightset_t_of< context_t_of< Lhs > >, weightset_t_of< context_t_of< Rhs > >> weightset_t
Definition: compose.hh:63
static labelset_t make_labelset_(const hidden_l_labelset_t &ll, const hidden_r_labelset_t &rl)
Definition: compose.hh:202
std::enable_if_t< labelset_t_of< Aut >::has_one(), res_label_t_of< Aut > > get_hidden_one(const insplit_automaton< Aut > &aut) const
Definition: compose.hh:253
res_labelset_t_of< crhs_t > hidden_r_labelset_t
Definition: compose.hh:54
auto & as()
Extract wrapped typed automaton.
Definition: automaton.hh:37
std::enable_if_t< labelset_t_of< Aut >::has_one(), bool > is_one(const Aut &aut, transition_t_of< Aut > tr) const
Definition: compose.hh:366
typename labelset_t::value_t label_t
Definition: compose.hh:177
typename detail::transition_t_of_impl< base_t< ValueSet > >::type transition_t_of
Definition: traits.hh:65
typename full_context_t_of_impl< Aut >::type full_context_t_of
Definition: compose.hh:42
constexpr std::enable_if_t<!labelset_t_of< Aut >::has_one(), bool > is_one(const Aut &, transition_t_of< Aut >) const
Definition: compose.hh:374
static auto real_aut(const A &aut)
Get the focus automaton, possibly from a non insplit automaton.
Definition: compose.hh:184
base_t< tuple_element_t< I, automata_t > > input_automaton_t
The type of the Ith input automaton, unqualified.
Definition: compose.hh:129
typename type_helper_t::weightset_t weightset_t
Definition: compose.hh:112
std::remove_cv_t< std::remove_reference_t< T > > base_t
T without reference or const/volatile qualifiers.
Definition: traits.hh:13
typename super_t::state_t state_t
Result state type.
Definition: compose.hh:120
auto all_in(const Aut &aut, state_t_of< Aut > s)
Indexes of transitions entering state s.
Definition: automaton.hh:116
typename res_label_t_of_impl< Aut >::type res_label_t_of
Definition: compose.hh:41