Awali
Another Weighted Automata library
compose.hh
Go to the documentation of this file.
1 // This file is part of Awali.
2 // Copyright 2016-2022 Sylvain Lombardy, Victor Marsault, Jacques Sakarovitch
3 //
4 // Awali is a free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 #ifndef AWALI_ALGOS_COMPOSE_HH
18 # define AWALI_ALGOS_COMPOSE_HH
19 
20 # include <stack>
21 # include <unordered_map>
22 
24 #include <awali/sttc/algos/sort.hh>
27 #include <awali/sttc/misc/sub_tuple.hh> // make_index_sequence
28 #include <awali/sttc/misc/add_epsilon_trans.hh> // is_epsilon
29 #include <awali/sttc/algos/projection.hh> // tuple_to_tupleset
33 
34 
35 namespace awali { namespace sttc {
36 
37  namespace internal
38  {
39  template<typename T> struct aff{};
40 
41 
42  /*---------------------------------.
43  | composer<automaton, automaton>. |
44  `---------------------------------*/
45 
46  template <typename T, size_t I> struct rem_in_tupleset;
47 
48  template <typename... T, size_t I>
49  struct rem_in_tupleset<tupleset<T...>,I>{
50  using tp_t = tupleset<T...>;
52 
53  static
54  type get(const tp_t& t) {
55  return {rem_in_tuple<I>::get(t.sets())};
56  }
57  };
58 
59  template <size_t I, size_t J, typename Tuple1, typename Tuple2>
60  auto
61  concat_and_remove(const Tuple1& t1, const Tuple2& t2)
62  -> typename std::concat_tuple<
63  typename rem_in_tuple<I>::template type<Tuple1>,
64  typename rem_in_tuple<J>::template type<Tuple2>>::type
65  {
66  return std::tuple_cat(rem_in_tuple<I>::get(t1),
68  }
69 
71 
72  template <typename Lhs, typename Rhs, size_t I, size_t J>
73  class composer
74  {
75  static_assert(Lhs::element_type::context_t::is_lat,
76  "requires labels_are_tuples");
77  static_assert(Rhs::element_type::context_t::is_lat,
78  "requires labels_are_tuples");
79  public:
80  using clhs_t = Lhs;
81  using crhs_t = Rhs;
86  using I_labelset_t = typename l_labelset_t::template valueset_t<I>;
87  using J_labelset_t = typename r_labelset_t::template valueset_t<J>;
90 
96 
99 
101  using pair_state_t = std::pair<state_t,state_t>;
102 
103  composer(const Lhs& lhs, const Rhs& rhs)
104  : lhs_(lhs),
105  rhs_(rhs),
106  output_(make_mutable_automaton(make_context_(lhs, rhs)))
107  {}
108 
110  const r_labelset_t& rl)
111  {
112  return {concat_and_remove<I,J>(ll.sets(),rl.sets())};
113  }
114 
115  static context_t
116  make_context_(const Lhs& lhs, const Rhs& rhs)
117  {
118  return {make_labelset_(*lhs->context().labelset(), *rhs->context().labelset()),
119  join(*lhs->weightset(), *rhs->weightset())};
120  }
121 
123  {
124  state_t res;
125  auto i = map_.find(ps);
126  if (i == std::end(map_))
127  {
128  res = output_->add_state();
129  map_[ps] = res;
130  todo_.push(ps);
131  }
132  else
133  res = i->second;
134  return res;
135  }
136 
139  {
140  pair_state_t ps{lhs_->pre(),rhs_->pre()};
141  map_[ps] = output_->pre();
142  todo_.push(ps);
143  map_[std::make_pair(lhs_->post(),rhs_->post())] = output_->post();
144  const auto& ws = *output_->context().weightset();
145  while (!todo_.empty())
146  {
147  ps = todo_.top();
148  todo_.pop();
149  state_t src = state(ps);
150  auto it1 = lhs_->all_out(ps.first).begin();
151  auto end1 = lhs_->all_out(ps.first).end();
152  if(it1 == end1)
153  continue;
154  if(is_epsilon<I_labelset_t>(std::get<I>(lhs_->label_of(*it1))))
155  for(auto tr:lhs_->all_out(ps.first)) {
156  state_t q = lhs_->dst_of(tr);
157  state_t dst = state(std::make_pair(q, ps.second));
158  output_->add_transition(src, dst,
159  std::tuple_cat(rem_in_tuple<I>::get(lhs_->label_of(tr)), get_epsilon<minusJ_labelset_t>()),
160  lhs_->weight_of(tr));
161  }
162  else {
163  auto it2 = rhs_->all_out(ps.second).begin();
164  auto end2 = rhs_->all_out(ps.second).end();
165  while(it2 != end2) {
166  const auto& tr2=*it2;
167  if(is_epsilon<J_labelset_t>(std::get<J>(rhs_->label_of(tr2)))) {
168  state_t q = rhs_->dst_of(tr2);
169  state_t dst = state(std::make_pair(ps.first, q));
170  output_->add_transition(src, dst,
171  std::tuple_cat(get_epsilon<minusI_labelset_t>(),rem_in_tuple<J>::get(rhs_->label_of(tr2))),
172  rhs_->weight_of(tr2));
173  ++it2;
174  }
175  else if(it1 == end1)
176  ++it2;
177  else if(I_labelset_t::less_than(std::get<I>(lhs_->label_of(*it1)),
178  std::get<J>(rhs_->label_of(tr2))))
179  ++it1;
180  else if(I_labelset_t::less_than(std::get<J>(rhs_->label_of(tr2)),
181  std::get<I>(lhs_->label_of(*it1))))
182  ++it2;
183  else {
184  auto begin1 = it1;
185  while(it2 != end2 && I_labelset_t::equals(std::get<I>(lhs_->label_of(*begin1)),
186  std::get<J>(rhs_->label_of(*it2)))) {
187  it1=begin1;
188  while(it1 != end1 &&I_labelset_t::equals(std::get<I>(lhs_->label_of(*it1)),
189  std::get<J>(rhs_->label_of(*it2)))) {
190  state_t q1 = lhs_->dst_of(*it1);
191  state_t q2 = rhs_->dst_of(*it2);
192  state_t dst = state(std::make_pair(q1, q2));
193  output_->add_transition(src, dst,
194  std::tuple_cat(rem_in_tuple<I>::get(lhs_->label_of(*it1)),
195  rem_in_tuple<J>::get(rhs_->label_of(*it2))),
196  ws.mul(lhs_->weight_of(*it1),rhs_->weight_of(*it2)));
197  ++it1;
198  }
199  ++it2;
200  }
201  }
202  }
203  }
204  }
205  return output_;
206  }
207 
208  void set_history() {
209  auto history = std::make_shared<tuple_history<std::tuple<Lhs,Rhs>>>(std::make_tuple(lhs_,rhs_));
210  output_->set_history(history);
211  for (const auto& p: map_)
212  history->add_state(p.second, p.first);
213  }
214 
215  private:
216  const Lhs& lhs_;
217  const Rhs& rhs_;
218  using label_t = typename labelset_t::value_t;
219  using weight_t = typename weightset_t::value_t;
220 
221  std::unordered_map<pair_state_t, state_t> map_;
222  std::stack<pair_state_t> todo_;
223 
224  automaton_t output_;
225  };
226  }
227 
228  /*--------------------------------.
229  | compose(automaton, automaton). |
230  `--------------------------------*/
253  template <size_t I, size_t J, typename TDC1, typename TDC2>
254  auto
255  composeIJ(TDC1& tdc1, TDC2& tdc2, bool keep_history=true)
257  {
258  auto l = tdc1;
259  if(!is_proper_tape<J>(tdc2))
260  l=outsplit<I>(tdc1, keep_history);
261  sort_tape<I>(l);
262  sort_tape<J>(tdc2);
264  auto r= compose.compose();
265  if(keep_history)
266  compose.set_history();
267  proper_here(r);
268  return r;
269  }
270 
283  template <typename TDC1, typename TDC2>
284  auto
285  compose(const TDC1& tdc1, const TDC2& tdc2, bool keep_history=true)
287  {
288  return composeIJ<1,0>(tdc1, tdc2, keep_history);
289  }
290 
303  template <typename Aut, typename Tdc>
304  auto
305  eval_tdc(const Aut& aut, const Tdc& tdc, bool keep_history=true)
306  -> decltype(projection<1>(tdc))
307  {
308  auto l = partial_identity<1>(aut,keep_history);
309  auto r = composeIJ<0,0>(l, tdc, keep_history);
310  return projection<0>(r,keep_history);
311  }
312 
313 }}//end of ns awali::stc
314 
315 
316 #endif // !AWALI_ALGOS_COMPOSE_HH
carries the algebraic settings of automata
Definition: context.hh:40
Build the (accessible part of the) composition.
Definition: compose.hh:74
weightset_t_of< Lhs > l_weightset_t
Definition: compose.hh:84
weightset_t_of< Rhs > r_weightset_t
Definition: compose.hh:85
typename rem_in_tupleset< r_labelset_t, J >::type minusJ_labelset_t
Definition: compose.hh:89
typename l_labelset_t::template valueset_t< I > I_labelset_t
Definition: compose.hh:86
mutable_automaton< context_t > automaton_t
The type of the resulting automaton.
Definition: compose.hh:98
std::pair< state_t, state_t > pair_state_t
Result state type.
Definition: compose.hh:101
static labelset_t make_labelset_(const l_labelset_t &ll, const r_labelset_t &rl)
Definition: compose.hh:109
labelset_t_of< Lhs > l_labelset_t
Definition: compose.hh:82
state_t state(const pair_state_t &ps)
Definition: compose.hh:122
Rhs crhs_t
Definition: compose.hh:81
typename rem_in_tupleset< l_labelset_t, I >::type minusI_labelset_t
Definition: compose.hh:88
Lhs clhs_t
Definition: compose.hh:80
automaton_t compose()
The (accessible part of the) product of lhs_ and rhs_.
Definition: compose.hh:138
labelset_t_of< Rhs > r_labelset_t
Definition: compose.hh:83
join_t< weightset_t_of< context_t_of< Lhs > >, weightset_t_of< context_t_of< Rhs > >> weightset_t
Definition: compose.hh:94
static context_t make_context_(const Lhs &lhs, const Rhs &rhs)
Definition: compose.hh:116
sttc::context< labelset_t, weightset_t > context_t
Definition: compose.hh:95
void set_history()
Definition: compose.hh:208
typename r_labelset_t::template valueset_t< J > J_labelset_t
Definition: compose.hh:87
composer(const Lhs &lhs, const Rhs &rhs)
Definition: compose.hh:103
typename concat_tupleset< minusI_labelset_t, minusJ_labelset_t >::type labelset_t
The type of context of the result.
Definition: compose.hh:92
The semiring of rational numbers.
Definition: q.hh:42
The semiring of floating Numbers.
Definition: r.hh:35
A ValueSet which is a Cartesian product of ValueSets.
Definition: tupleset.hh:80
const valuesets_t & sets() const
The componants valuesets, as a tuple.
Definition: tupleset.hh:152
auto concat_and_remove(const Tuple1 &t1, const Tuple2 &t2) -> typename std::concat_tuple< typename rem_in_tuple< I >::template type< Tuple1 >, typename rem_in_tuple< J >::template type< Tuple2 >>::type
Definition: compose.hh:61
Definition: compose.hh:39
Definition: tupleset.hh:959
Definition: projection.hh:52
RatExpSet::ratexp_t less_than(const RatExpSet &rs, const typename RatExpSet::ratexp_t &v)
Definition: less_than.hh:166
auto composeIJ(TDC1 &tdc1, TDC2 &tdc2, bool keep_history=true) -> typename internal::composer< TDC1, TDC2, I, J >::automaton_t
Composition of two transducers on given tapes.
Definition: compose.hh:255
auto compose(const TDC1 &tdc1, const TDC2 &tdc2, bool keep_history=true) -> typename internal::composer< TDC1, TDC2, 1, 0 >::automaton_t
Composition of two transducers.
Definition: compose.hh:285
RatExpSet::ratexp_t equals(const RatExpSet &rs, const typename RatExpSet::ratexp_t &v)
Definition: equal_visit.hh:153
decltype(join(std::declval< ValueSets >()...)) join_t
Computation of the join of some value sets.
Definition: context.hh:210
auto join(const ratexpset< Ctx1 > &a, const ratexpset< Ctx2 > &b) -> ratexpset< join_t< Ctx1, Ctx2 >>
The union of two ratexpsets.
Definition: ratexpset.hh:445
typename internal::labelset_t_of_impl< internal::base_t< ValueSet > >::type labelset_t_of
Helper to retrieve the type of the labelset of a value set.
Definition: traits.hh:76
mutable_automaton< Context > make_mutable_automaton(const Context &ctx)
Definition: mutable_automaton.hh:915
auto eval_tdc(const Aut &aut, const Tdc &tdc, bool keep_history=true) -> decltype(projection< 1 >(tdc))
Evaluation of an automaton by a transducer.
Definition: compose.hh:305
void proper_here(Aut &aut, direction_t dir=BACKWARD, bool prune=true)
Eliminate spontaneous transitions in place.
Definition: proper.hh:427
std::shared_ptr< internal::mutable_automaton_impl< Context > > mutable_automaton
Definition: mutable_automaton.hh:45
typename internal::weightset_t_of_impl< internal::base_t< ValueSet > >::type weightset_t_of
Helper to retrieve the type of the weightset of a value set.
Definition: traits.hh:86
Main namespace of Awali.
Definition: ato.hh:22
unsigned state_t
Definition: types.hh:21
Definition: sub_tuple.hh:111
static auto get(const Tuple &t) -> type< Tuple >
Definition: sub_tuple.hh:119
static type get(const tp_t &t)
Definition: compose.hh:54
typename tuple_to_tupleset< typename rem_in_tuple< I >::template type< std::tuple< T... > >>::type type
Definition: compose.hh:51
Definition: tuple.hh:365