Vcsn  2.2
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  {
20 #define DEFINE(Type) \
21  template <Automaton Aut> \
22  struct Type ## _of_impl \
23  { \
24  using type = typename Aut::element_type::Type; \
25  }; \
26  \
27  template <Automaton Aut> \
28  struct Type ## _of_impl<insplit_automaton<Aut>> \
29  : Type ## _of_impl<Aut> \
30  {}; \
31  \
32  template <Automaton Aut> \
33  using Type ## _of \
34  = typename Type ## _of_impl<Aut>::type
35 
36  DEFINE(res_labelset_t);
37  DEFINE(res_label_t);
38  DEFINE(full_context_t);
39 
40 #undef DEFINE
41 
43  template <Automaton Lhs, Automaton Rhs>
45  {
46  using clhs_t = Lhs;
47  using crhs_t = Rhs;
48  // clhs_t and crhs_t are permutation automata, yet we need to
49  // read the res_label_t from their wrapped automaton type.
52  using hidden_l_label_t = typename hidden_l_labelset_t::value_t;
53  using hidden_r_label_t = typename hidden_r_labelset_t::value_t;
54 
55 
61 
62  using res_label_t = typename labelset_t::value_t;
64 
66 
69  Lhs, Rhs>;
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 
124  using super_t::aut_;
125 
126  static symbol sname()
127  {
128  static symbol res(std::string{"compose_automaton<"}
129  + (Lazy ? "true" : "false") + ", "
130  + Lhs::element_type::sname() + ", "
131  + Rhs::element_type::sname() + ">");
132  return res;
133  }
134 
135  std::ostream& print_set(std::ostream& o, format fmt = {}) const
136  {
137  o << "compose_automaton<";
138  std::get<0>(aut_->auts_)->print_set(o, fmt) << ", ";
139  return std::get<1>(aut_->auts_)->print_set(o, fmt) << ">";
140  }
141 
142  compose_automaton_impl(const Lhs& lhs, const Rhs& rhs)
143  : super_t{make_mutable_automaton(make_context_(lhs, rhs)), lhs, rhs}
144  {}
145 
147  void compose()
148  {
150 
151  if (!Lazy)
152  while (!aut_->todo_.empty())
153  {
154  const auto& p = aut_->todo_.front();
155  this->complete_(std::get<1>(p));
156  aut_->todo_.pop_front();
157  }
158  }
159 
160 
161  void add_transitions(const state_t src,
162  const state_name_t& psrc)
163  {
164  add_compose_transitions(src, psrc);
165  }
166 
167  using label_t = typename labelset_t::value_t;
168  using weight_t = typename weightset_t::value_t;
169  private:
170 
171  template <Automaton A>
172  static auto real_aut(const A& aut)
173  {
174  return aut;
175  }
176 
177  template <Automaton A>
178  static auto real_aut(const insplit_automaton<A>& aut)
179  {
180  return aut->aut_out();
181  }
182 
185  template <Automaton A>
186  using transition_map_t
188 
190  const hidden_r_labelset_t& rl)
191  {
194  }
195 
196  template <std::size_t... I1, std::size_t... I2>
198  seq<I1...>,
199  const hidden_r_labelset_t& rl,
200  seq<I2...>)
201  {
202  return labelset_t{std::get<I1>(ll.sets())...,
203  std::get<I2>(rl.sets())...};
204  }
205 
206  static context_t
207  make_context_(const Lhs& lhs, const Rhs& rhs)
208  {
209  return {make_labelset_(lhs->res_labelset(),
210  real_aut(rhs)->res_labelset()),
211  join(*lhs->weightset(), *rhs->weightset())};
212  }
213 
217  {
218  aut_->todo_.emplace_back(aut_->pre_(), aut_->pre());
219  }
220 
222  const hidden_r_label_t& rl) const
223  {
224  return std::tuple_cat(ll, rl);
225  }
226 
227  template <Automaton Aut>
228  std::enable_if_t<labelset_t_of<Aut>::has_one(),
230  get_hidden_one(const Aut& aut) const
231  {
232  return aut->hidden_one();
233  }
234 
235  template <Automaton Aut>
236  std::enable_if_t<labelset_t_of<Aut>::has_one(),
239  {
240  return real_aut(aut)->hidden_one();
241  }
242 
243  template <Automaton Aut>
244  ATTRIBUTE_NORETURN
245  std::enable_if_t<!labelset_t_of<Aut>::has_one(),
247  get_hidden_one(const Aut&) const
248  {
249  raise("should not get here");
250  }
251 
258  const state_name_t& psrc)
259  {
260  const auto& lhs = std::get<0>(aut_->auts_);
261  const auto& rhs = std::get<1>(aut_->auts_);
262 
263  // Outgoing transition cache.
264  const auto& ltm = std::get<0>(transition_maps_)[std::get<0>(psrc)];
265  const auto& rtm = std::get<1>(transition_maps_)[std::get<1>(psrc)];
266 
267  bool has_eps_out = false;
268  if (!is_spontaneous_in(rhs, std::get<1>(psrc))
269  // "Loop" only on the spontaneous transitions. "One" is
270  // guaranteed to be first in the transition maps.
271  && !ltm.empty()
272  && lhs->labelset()->is_one(ltm.begin()->first))
273  {
274  has_eps_out = true;
275  // for each spontaneous transitions leaving the state
276  for (auto t: ltm.begin()->second)
277  this->new_transition(src,
278  this->state(t.dst, std::get<1>(psrc)),
279  join_label(lhs->hidden_label_of(t.transition),
280  get_hidden_one(rhs->aut_out())),
281  t.weight());
282  }
283 
284  // If lhs did not issue spontaneous transitions but has proper
285  // transitions, issue follow all the rhs spontaneous
286  // transitions.
287  const bool lhs_has_proper_trans =
288  !ltm.empty()
289  && (!lhs->labelset()->is_one(ltm.begin()->first)
290  || 2 <= ltm.size());
291 
292  if ((!has_eps_out || lhs_has_proper_trans)
293  && !rtm.empty()
294  && rhs->labelset()->is_one(rtm.begin()->first))
295  for (auto t: rtm.begin()->second)
296  this->new_transition(src,
297  this->state(std::get<0>(psrc), t.dst),
299  real_aut(rhs)->hidden_label_of(t.transition)),
300  t.weight());
301 
302 
303  // In order to avoid having to call add_transition each time, we cache
304  // the transitions we add using a polynomial. We conserve a polynomial
305  // for each successor of src.
307  using polynomial_t = typename polynomialset_t::value_t;
308  const auto ps = polynomialset_t(aut_->context());
309  auto poly_maps = std::map<state_t, polynomial_t>();
310 
311  for (auto t: zip_maps(ltm, rtm))
312  // The type of the common label is that of the visible tape
313  // of either automata.
314  if (!lhs->labelset()->is_one(t.first))
315  // These may not be new transitions: as the automata are focus,
316  // there might be two transitions with the same destination and
317  // label, with only the hidden part that changes.
319  ([&] (const typename transition_map_t<Lhs>::transition& lts,
320  const typename transition_map_t<Rhs>::transition& rts)
321  {
322  // Cache the transitions.
323  ps.add_here(poly_maps[this->state(lts.dst, rts.dst)],
324  join_label(lhs->hidden_label_of(lts.transition),
325  real_aut(rhs)->hidden_label_of(rts.transition)),
326  this->weightset()->mul(lts.weight(), rts.weight()));
327  },
328  t.second);
329 
330  // For each successor, add a transition for each monomial of the
331  // corresponding polynomial.
332  for (auto elt: poly_maps)
333  for (auto m: elt.second)
334  this->new_transition(src, elt.first, m.first, m.second);
335  }
336 
337  template <Automaton Aut>
338  std::enable_if_t<labelset_t_of<Aut>::has_one(), bool>
339  is_one(const Aut& aut, transition_t_of<Aut> tr) const
340  {
341  return aut->labelset()->is_one(aut->label_of(tr));
342  }
343 
344  template <Automaton Aut>
345  constexpr
346  std::enable_if_t<!labelset_t_of<Aut>::has_one(), bool>
347  is_one(const Aut&, transition_t_of<Aut>) const
348  {
349  return false;
350  }
351 
355  template <Automaton Aut>
356  constexpr
357  std::enable_if_t<!labelset_t_of<Aut>::has_one(), bool>
359  {
360  return false;
361  }
362 
367  template <Automaton Aut>
368  std::enable_if_t<labelset_t_of<Aut>::has_one(), bool>
369  is_spontaneous_in(const Aut& rhs, state_t_of<Aut> rst) const
370  {
371  auto rin = all_in(rhs, rst);
372  auto rtr = rin.begin();
373  return rtr != rin.end() && is_one(rhs, *rtr);
374  }
375  };
376  }
377 
379  template <bool Lazy, Automaton Lhs, Automaton Rhs>
380  using compose_automaton
381  = std::shared_ptr<detail::compose_automaton_impl<Lazy, Lhs, Rhs>>;
382 
383  template <bool Lazy, std::size_t OutTape, std::size_t InTape,
384  Automaton Lhs, Automaton Rhs>
385  auto
386  make_compose_automaton(const Lhs& lhs, const Rhs& rhs)
387  {
388  auto l = focus<OutTape>(lhs);
389  auto r = insplit_lazy(focus<InTape>(rhs));
390  using res_t = compose_automaton<Lazy,
392  decltype(r)>;
393  return make_shared_ptr<res_t>(l, r);
394  }
395 
396  /*--------------------------------.
397  | compose(automaton, automaton). |
398  `--------------------------------*/
399 
401  template <Automaton Lhs, Automaton Rhs,
402  std::size_t OutTape = 1, std::size_t InTape = 0>
403  auto
404  compose(Lhs& lhs, Rhs& rhs)
405  {
406  auto res = make_compose_automaton<false, OutTape, InTape>(lhs, rhs);
407  res->compose();
408  return res->strip();
409  }
410 
412  template <typename Lhs, typename Rhs,
413  std::size_t OutTape = 1, std::size_t InTape = 0>
414  auto
415  compose_lazy(Lhs& lhs, Rhs& rhs)
416  {
417  auto res = make_compose_automaton<true, OutTape, InTape>(lhs, rhs);
418  res->compose();
419  return res;
420  }
421 
422  namespace dyn
423  {
424  namespace detail
425  {
427  template <Automaton Lhs, Automaton Rhs, typename Bool>
428  automaton
429  compose(automaton& lhs, automaton& rhs, bool lazy)
430  {
431  auto& l = lhs->as<Lhs>();
432  auto& r = rhs->as<Rhs>();
433  if (lazy)
434  return make_automaton(::vcsn::compose_lazy(l, r));
435  else
436  return make_automaton(::vcsn::compose(l, r));
437  }
438  }
439  }
440 }
auto weightset(Args &&...args) const -> decltype(aut_-> weightset(std::forward< Args >(args)...))
std::shared_ptr< detail::focus_automaton_impl< Tape, Aut >> focus_automaton
A focus automaton as a shared pointer.
Definition: fwd.hh:42
auto join(const ValueSet &vs) -> ValueSet
The join of a single valueset.
Definition: join.hh:44
compose_automaton_impl(const Lhs &lhs, const Rhs &rhs)
Definition: compose.hh:142
tuple_automaton< mutable_automaton< context_t >, Lhs, Rhs > automaton_t
The type of the resulting automaton.
Definition: compose.hh:69
std::shared_ptr< detail::insplit_automaton_impl< Aut, labelset_t_of< Aut >::has_one()>> insplit_automaton
A compose automaton as a shared pointer.
Definition: insplit.hh:312
typename type_helper_t::hidden_r_label_t hidden_r_label_t
Definition: compose.hh:107
typename full_context_t_of_impl< Aut >::type full_context_t_of
Definition: compose.hh:38
Decorator implementing the laziness for an algorithm.
automaton make_automaton(const Aut &aut)
Build a dyn::automaton.
Definition: automaton.hh:75
decltype(join(std::declval< ValueSets >()...)) join_t
The type of the join of the ValueSets.
Definition: join.hh:79
auto compose(Lhs &lhs, Rhs &rhs)
Build the (accessible part of the) composition.
Definition: compose.hh:404
typename res_label_t_of_impl< Aut >::type res_label_t_of
Definition: compose.hh:37
typename super_t::state_name_t state_name_t
Tuple of states of input automata.
Definition: compose.hh:122
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:59
typename type_helper_t::context_t context_t
Definition: compose.hh:115
auto all_in(Args &&...args) const -> decltype(aut_-> all_in(std::forward< Args >(args)...))
std::shared_ptr< detail::mutable_automaton_impl< Context >> mutable_automaton
Definition: fwd.hh:25
void initialize_compose()
Fill the worklist with the initial source-state pairs, as needed for the composition algorithm...
Definition: compose.hh:216
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:339
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:257
Definition: a-star.hh:8
typename type_helper_t::hidden_l_labelset_t hidden_l_labelset_t
Definition: compose.hh:104
auto make_compose_automaton(const Lhs &lhs, const Rhs &rhs)
Definition: compose.hh:386
transition_map< A, weightset_t, false, true, true > transition_map_t
The type of our transition maps: convert the weight to weightset_t, non deterministic, and including transitions to post().
Definition: compose.hh:187
static auto real_aut(const insplit_automaton< A > &aut)
Definition: compose.hh:178
constexpr std::enable_if_t<!labelset_t_of< Aut >::has_one(), bool > is_one(const Aut &, transition_t_of< Aut >) const
Definition: compose.hh:347
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:230
res_labelset_t_of< clhs_t > hidden_l_labelset_t
Definition: compose.hh:50
typename labelset_t::value_t res_label_t
Definition: compose.hh:62
void add_transitions(const state_t src, const state_name_t &psrc)
Definition: compose.hh:161
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
typename hidden_l_labelset_t::value_t hidden_l_label_t
Definition: compose.hh:52
std::string type(const automaton &a)
The implementation type of a.
Definition: others.cc:206
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
::vcsn::context< labelset_t, weightset_t > context_t
Definition: compose.hh:63
An input/output format for valuesets.
Definition: format.hh:11
typename weightset_t::value_t weight_t
Definition: compose.hh:168
typename type_helper_t::hidden_l_label_t hidden_l_label_t
Definition: compose.hh:106
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
Cache the outgoing transitions of an automaton as efficient maps label -> vector<(weight, dst)>.
typename labelset_t::value_t label_t
Definition: compose.hh:167
auto compose_lazy(Lhs &lhs, Rhs &rhs)
Build the (accessible part of the) laze composition.
Definition: compose.hh:415
auto insplit_lazy(const Aut &aut) -> decltype(make_insplit_automaton(aut))
Definition: insplit.hh:325
std::enable_if_t< L, void > complete_(state_t s) const
Complete a state: find its outgoing transitions.
res_label_t join_label(const hidden_l_label_t &ll, const hidden_r_label_t &rl) const
Definition: compose.hh:221
static auto real_aut(const A &aut)
Definition: compose.hh:172
typename detail::state_t_of_impl< base_t< ValueSet >>::type state_t_of
Definition: traits.hh:56
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:238
constexpr std::enable_if_t<!labelset_t_of< Aut >::has_one(), bool > is_spontaneous_in(const Aut &, state_t_of< Aut >) const
Check if the state has only incoming spontaneous transitions.
Definition: compose.hh:358
join_t< weightset_t_of< context_t_of< Lhs >>, weightset_t_of< context_t_of< Rhs >>> weightset_t
Definition: compose.hh:60
std::shared_ptr< detail::tuple_automaton_impl< Auts... >> tuple_automaton
A tuple automaton as a shared pointer.
#define DEFINE(Type)
Definition: compose.hh:20
void cross_tuple(Fun f, const std::tuple< Ts... > &ts)
Definition: tuple.hh:235
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:247
mutable_automaton< context_t > out_t
Definition: compose.hh:65
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:23
std::tuple< transition_map_t< Auts >... > transition_maps_
Transition caches.
std::shared_ptr< detail::automaton_base > automaton
Definition: automaton.hh:69
typename detail::transition_t_of_impl< base_t< ValueSet >>::type transition_t_of
Definition: traits.hh:57
auto new_transition(Args &&...args) -> decltype(aut_-> new_transition(std::forward< Args >(args)...))
Build the (accessible part of the) composition.
Definition: compose.hh:44
void compose()
The (accessible part of the) composition of lhs_ and rhs_.
Definition: compose.hh:147
static labelset_t make_labelset_(const hidden_l_labelset_t &ll, const hidden_r_labelset_t &rl)
Definition: compose.hh:189
symbol sname()
Definition: name.hh:67
typename tuple_automaton_t::element_type::state_t state_t
typename concat_tupleset< hidden_l_labelset_t, hidden_r_labelset_t >::type labelset_t
The type of context of the result.
Definition: compose.hh:58
typename tuple_automaton_t::element_type::state_name_t state_name_t
typename super_t::state_t state_t
Result state type.
Definition: compose.hh:120
typename type_helper_t::res_label_t res_label_t
Definition: compose.hh:114
static context_t make_context_(const Lhs &lhs, const Rhs &rhs)
Definition: compose.hh:207
mutable_automaton< Context > make_mutable_automaton(const Context &ctx)
typename type_helper_t::hidden_r_labelset_t hidden_r_labelset_t
Definition: compose.hh:105
std::shared_ptr< detail::compose_automaton_impl< Lazy, Lhs, Rhs >> compose_automaton
A compose automaton as a shared pointer.
Definition: compose.hh:381
std::ostream & print_set(std::ostream &o, format fmt={}) const
Definition: compose.hh:135
typename res_labelset_t_of_impl< Aut >::type res_labelset_t_of
Definition: compose.hh:36
#define Automaton
Definition: automaton.hh:24
typename hidden_r_labelset_t::value_t hidden_r_label_t
Definition: compose.hh:53
size_t size(const ExpSet &rs, const typename ExpSet::value_t &r)
typename type_helper_t::labelset_t labelset_t
The type of context of the result.
Definition: compose.hh:111
zipped_maps< Dereference, Maps... > zip_maps(Maps &&...maps)
Definition: zip-maps.hh:250
typename type_helper_t::out_t out_t
Definition: compose.hh:117
res_labelset_t_of< crhs_t > hidden_r_labelset_t
Definition: compose.hh:51
std::enable_if_t< labelset_t_of< Aut >::has_one(), bool > is_spontaneous_in(const Aut &rhs, state_t_of< Aut > rst) const
Whether the state has only incoming spontaneous transitions.
Definition: compose.hh:369
Build the (accessible part of the) composition.
Definition: compose.hh:79
static labelset_t make_labelset_(const hidden_l_labelset_t &ll, seq< I1... >, const hidden_r_labelset_t &rl, seq< I2... >)
Definition: compose.hh:197
Outgoing signature: weight, destination.
typename type_helper_t::weightset_t weightset_t
Definition: compose.hh:112