Vcsn  2.1
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>
7 #include <vcsn/ctx/context.hh>
8 #include <vcsn/dyn/automaton.hh> // dyn::make_automaton
10 #include <vcsn/misc/raise.hh>
11 #include <vcsn/misc/tuple.hh> // make_index_sequence, cross_tuple
12 #include <vcsn/misc/zip-maps.hh>
13 
14 namespace vcsn
15 {
16  namespace detail
17  {
18  /*---------------------------------.
19  | composer<automaton, automaton>. |
20  `---------------------------------*/
21 
23  template <typename Lhs, typename Rhs>
24  class composer
25  {
26  static_assert(Lhs::element_type::full_context_t::is_lat,
27  "compose: lhs labelset must be a tupleset");
28  static_assert(Rhs::element_type::full_context_t::is_lat,
29  "compose: rhs labelset must be a tupleset");
30 
32  template <std::size_t... I>
34 
35  public:
36  using clhs_t = Lhs;
37  using crhs_t = Rhs;
38  // clhs_t and crhs_t are permutation automata, yet we need to
39  // read the res_label_t from their wrapped automaton type.
40  using hidden_l_labelset_t = typename clhs_t::element_type::res_labelset_t;
41  using hidden_r_labelset_t = typename crhs_t::element_type::res_labelset_t;
42  using hidden_l_label_t = typename hidden_l_labelset_t::value_t;
43  using hidden_r_label_t = typename hidden_r_labelset_t::value_t;
44 
45  static_assert(std::is_same<labelset_t_of<clhs_t>,
46  labelset_t_of<crhs_t>>::value,
47  "compose: common tape must be of same type");
48 
60 
61  using res_label_t = typename labelset_t::value_t;
63 
66  Lhs, Rhs>;
67 
71  using state_name_t = typename automaton_t::element_type::state_name_t;
72 
73  composer(const Lhs& lhs, const Rhs& rhs)
75  lhs, rhs))
76  , transition_maps_{{lhs, *res_->weightset()},
77  {rhs, *res_->weightset()}}
78  {}
79 
81  automaton_t operator()()
82  {
84 
85  while (!res_->todo_.empty())
86  {
87  const auto& p = res_->todo_.front();
88  add_compose_transitions(std::get<1>(p), std::get<0>(p));
89  res_->todo_.pop_front();
90  }
91  return std::move(res_);
92  }
93 
94  private:
95  using label_t = typename labelset_t::value_t;
96  using weight_t = typename weightset_t::value_t;
97 
100  template <typename A>
101  using transition_map_t
103 
104  static labelset_t make_labelset_(const hidden_l_labelset_t& ll,
105  const hidden_r_labelset_t& rl)
106  {
109  }
110 
111  template <std::size_t... I1, std::size_t... I2>
112  static labelset_t make_labelset_(const hidden_l_labelset_t& ll,
113  seq<I1...>,
114  const hidden_r_labelset_t& rl,
115  seq<I2...>)
116  {
117  return labelset_t{std::get<I1>(ll.sets())...,
118  std::get<I2>(rl.sets())...};
119  }
120 
121  static context_t
122  make_context_(const Lhs& lhs, const Rhs& rhs)
123  {
124  return {make_labelset_(lhs->res_labelset(), rhs->res_labelset()),
125  join(*lhs->weightset(), *rhs->weightset())};
126  }
127 
131  {
132  res_->todo_.emplace_back(res_->pre_(), res_->pre());
133  }
134 
136  const hidden_r_label_t& rl)
137  {
138  return std::tuple_cat(ll, rl);
139  }
140 
141  template<typename Aut>
143  typename Aut::element_type::res_label_t>
144  get_hidden_one(const Aut& aut)
145  {
146  return aut->hidden_one();
147  }
148 
149  template<typename Aut>
151  typename Aut::element_type::res_label_t>
152  get_hidden_one(const Aut&)
153  {
154  raise("should not get here");
155  }
156 
162  const state_name_t& psrc)
163  {
164  auto& lhs = std::get<0>(res_->auts_);
165  auto& rhs = std::get<1>(res_->auts_);
166 
167  // Outgoing transition cache.
168  const auto& ltm = std::get<0>(transition_maps_)[std::get<0>(psrc)];
169  const auto& rtm = std::get<1>(transition_maps_)[std::get<1>(psrc)];
170 
171  bool has_eps_out = false;
172  if (!is_spontaneous_in(rhs, std::get<1>(psrc))
173  // "Loop" only on the spontaneous transitions. "One" is
174  // guaranteed to be first in the transition maps.
175  && !ltm.empty()
176  && lhs->labelset()->is_one(ltm.begin()->first))
177  {
178  has_eps_out = true;
179  for (auto t: ltm.begin()->second)
180  res_->new_transition(src,
181  res_->state(t.dst, std::get<1>(psrc)),
182  join_label(lhs->hidden_label_of(t.transition),
183  get_hidden_one(rhs)),
184  t.weight());
185  }
186 
187  // If lhs did not issue spontaneous transitions but has proper
188  // transitions, issue follow all the rhs spontaneous
189  // transitions.
190  const bool lhs_has_proper_trans =
191  !ltm.empty()
192  && (!lhs->labelset()->is_one(ltm.begin()->first)
193  || 2 <= ltm.size());
194 
195  if ((!has_eps_out || lhs_has_proper_trans)
196  && !rtm.empty()
197  && rhs->labelset()->is_one(rtm.begin()->first))
198  for (auto t: rtm.begin()->second)
199  res_->new_transition(src,
200  res_->state(std::get<0>(psrc), t.dst),
202  rhs->hidden_label_of(t.transition)),
203  t.weight());
204 
205  for (auto t: zip_maps(ltm, rtm))
206  // The type of the common label is that of the visible tape
207  // of either automata.
208  if (!lhs->labelset()->is_one(t.first))
209  // These are always new transitions: first because the
210  // source state is visited for the first time, and second
211  // because the couple (left destination, label) is unique,
212  // and so is (right destination, label).
214  ([&] (const typename transition_map_t<Lhs>::transition& lts,
215  const typename transition_map_t<Rhs>::transition& rts)
216  {
217  res_->new_transition
218  (src,
219  res_->state(lts.dst, rts.dst),
220  join_label(lhs->hidden_label_of(lts.transition),
221  rhs->hidden_label_of(rts.transition)),
222  res_->weightset()->mul(lts.weight(), rts.weight()));
223  },
224  t.second);
225  }
226 
227  template <typename A>
229  is_one(const A& aut, transition_t_of<A> tr) const
230  {
231  return aut->labelset()->is_one(aut->label_of(tr));
232  }
233 
234  template <typename A>
235  constexpr
238  const
239  {
240  return false;
241  }
242 
246  template <typename Aut>
247  constexpr
250  {
251  return false;
252  }
253 
258  template <typename Aut>
260  is_spontaneous_in(const Aut& rhs, state_t_of<Aut> rst) const
261  {
262  auto rin = rhs->all_in(rst);
263  auto rtr = rin.begin();
264  return rtr != rin.end() && is_one(rhs, *rtr);
265  }
266 
270  std::tuple<transition_map_t<Lhs>, transition_map_t<Rhs>> transition_maps_;
271  };
272 
273  template <typename Lhs, typename Rhs>
274  auto
275  make_composer(Lhs& lhs, Rhs& rhs)
276  -> typename detail::composer<Lhs, Rhs>
277  {
278  return detail::composer<Lhs, Rhs>{lhs, rhs};
279  }
280  }
281 
282  /*--------------------------------.
283  | compose(automaton, automaton). |
284  `--------------------------------*/
285 
287  template <typename Lhs, typename Rhs,
288  unsigned OutTape = 1, unsigned InTape = 0>
289  auto
290  compose(Lhs& lhs, Rhs& rhs)
293  {
294  auto l = focus<OutTape>(lhs);
295  auto r = insplit(focus<InTape>(rhs));
296  auto compose = detail::make_composer(l, r);
297  return compose();
298  }
299 
300  namespace dyn
301  {
302  namespace detail
303  {
305  template <typename Lhs, typename Rhs>
306  automaton
308  {
309  auto& l = lhs->as<Lhs>();
310  auto& r = rhs->as<Rhs>();
311  return make_automaton(::vcsn::compose(l, r));
312  }
313  }
314  }
315 }
constexpr vcsn::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:249
join_t< weightset_t_of< context_t_of< Lhs >>, weightset_t_of< context_t_of< Rhs >>> weightset_t
Definition: compose.hh:59
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:161
composer(const Lhs &lhs, const Rhs &rhs)
Definition: compose.hh:73
static context_t make_context_(const Lhs &lhs, const Rhs &rhs)
Definition: compose.hh:122
Outgoing signature: weight, destination.
res_label_t join_label(const hidden_l_label_t &ll, const hidden_r_label_t &rl)
Definition: compose.hh:135
typename labelset_t::value_t res_label_t
Definition: compose.hh:61
std::string type(const automaton &a)
The implementation type of a.
Definition: others.cc:197
constexpr vcsn::enable_if_t<!labelset_t_of< A >::has_one(), bool > is_one(const A &, transition_t_of< A >) const
Definition: compose.hh:237
auto join(const ValueSet &vs) -> ValueSet
The join of a single valueset.
Definition: join.hh:44
static labelset_t make_labelset_(const hidden_l_labelset_t &ll, const hidden_r_labelset_t &rl)
Definition: compose.hh:104
vcsn::enable_if_t< labelset_t_of< Aut >::has_one(), typename Aut::element_type::res_label_t > get_hidden_one(const Aut &aut)
Definition: compose.hh:144
typename detail::state_t_of_impl< base_t< ValueSet >>::type state_t_of
Definition: traits.hh:48
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:51
typename std::enable_if< Cond, T >::type enable_if_t
Definition: type_traits.hh:16
typename crhs_t::element_type::res_labelset_t hidden_r_labelset_t
Definition: compose.hh:41
auto make_composer(Lhs &lhs, Rhs &rhs) -> typename detail::composer< Lhs, Rhs >
Definition: compose.hh:275
void cross_tuple(Fun f, const std::tuple< Ts...> &ts)
Definition: tuple.hh:235
typename clhs_t::element_type::res_labelset_t hidden_l_labelset_t
Definition: compose.hh:40
vcsn::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:260
typename weightset_t::value_t weight_t
Definition: compose.hh:96
SharedPtr make_shared_ptr(Args &&...args)
Same as std::make_shared, but parameterized by the shared_ptr type, not the (pointed to) element_type...
Definition: memory.hh:14
zipped_maps< Dereference, Maps...> zip_maps(Maps &&...maps)
Definition: zip-maps.hh:250
std::tuple< transition_map_t< Lhs >, transition_map_t< Rhs > > transition_maps_
Transition caches.
Definition: compose.hh:270
vcsn::enable_if_t< labelset_t_of< A >::has_one(), bool > is_one(const A &aut, transition_t_of< A > tr) const
Definition: compose.hh:229
automaton make_automaton(const Aut &aut)
Build a dyn::automaton.
Definition: automaton.hh:75
mutable_automaton< Context > make_mutable_automaton(const Context &ctx)
vcsn::enable_if_t< labelset_t_of< Aut >::has_one(), Aut > insplit(Aut &aut)
Definition: insplit.hh:90
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
std::shared_ptr< detail::tuple_automaton_impl< Auts...>> tuple_automaton
A tuple automaton as a shared pointer.
typename automaton_t::element_type::state_name_t state_name_t
Tuple of states of input automata.
Definition: compose.hh:71
std::shared_ptr< detail::automaton_base > automaton
Definition: automaton.hh:69
Build the (accessible part of the) composition.
Definition: compose.hh:24
size_t size(const ExpSet &rs, const typename ExpSet::value_t &r)
decltype(join(std::declval< ValueSets >()...)) join_t
The type of the join of the ValueSets.
Definition: join.hh:79
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
Definition: traits.hh:47
labelset_t_of< clhs_t > middle_labelset_t
Definition: compose.hh:49
typename detail::transition_t_of_impl< base_t< ValueSet >>::type transition_t_of
Definition: traits.hh:49
typename concat_tupleset< hidden_l_labelset_t, hidden_r_labelset_t >::type labelset_t
The type of context of the result.
Definition: compose.hh:57
automaton_t res_
The computed product.
Definition: compose.hh:268
Cache the outgoing transitions of an automaton as efficient maps label -> vector<(weight, dst)>.
tuple_automaton< mutable_automaton< context_t >, Lhs, Rhs > automaton_t
The type of the resulting automaton.
Definition: compose.hh:66
std::shared_ptr< detail::focus_automaton_impl< Tape, Aut >> focus_automaton
A focus automaton as a shared pointer.
Definition: fwd.hh:41
void initialize_compose()
Fill the worklist with the initial source-state pairs, as needed for the product algorithm.
Definition: compose.hh:130
typename hidden_r_labelset_t::value_t hidden_r_label_t
Definition: compose.hh:43
typename hidden_l_labelset_t::value_t hidden_l_label_t
Definition: compose.hh:42
state_t_of< automaton_t > state_t
Result state type.
Definition: compose.hh:69
static labelset_t make_labelset_(const hidden_l_labelset_t &ll, seq< I1...>, const hidden_r_labelset_t &rl, seq< I2...>)
Definition: compose.hh:112
vcsn::enable_if_t<!labelset_t_of< Aut >::has_one(), typename Aut::element_type::res_label_t > get_hidden_one(const Aut &)
Definition: compose.hh:152
auto compose(Lhs &lhs, Rhs &rhs) -> typename detail::composer< focus_automaton< OutTape, Lhs >, focus_automaton< InTape, Rhs >>::automaton_t
Build the (accessible part of the) composition.
Definition: compose.hh:290