Awali
Another Weighted Automata library
compose.hh
Go to the documentation of this file.
1 // This file is part of Awali.
2 // Copyright 2016-2021 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>
26 #include <awali/sttc/misc/sub_tuple.hh> // make_index_sequence
27 #include <awali/sttc/misc/add_epsilon_trans.hh> // is_epsilon
28 #include <awali/sttc/algos/projection.hh> // tuple_to_tupleset
32 
33 
34 namespace awali { namespace sttc {
35 
36  namespace internal
37  {
38  template<typename T> struct aff{};
39 
40 
41  /*---------------------------------.
42  | composer<automaton, automaton>. |
43  `---------------------------------*/
44 
45  template <typename T, size_t I> struct rem_in_tupleset;
46 
47  template <typename... T, size_t I>
48  struct rem_in_tupleset<tupleset<T...>,I>{
49  using tp_t = tupleset<T...>;
51 
52  static
53  type get(const tp_t& t) {
54  return {rem_in_tuple<I>::get(t.sets())};
55  }
56  };
57 
58  template <size_t I, size_t J, typename Tuple1, typename Tuple2>
59  auto
60  concat_and_remove(const Tuple1& t1, const Tuple2& t2)
61  -> typename std::concat_tuple<
62  typename rem_in_tuple<I>::template type<Tuple1>,
63  typename rem_in_tuple<J>::template type<Tuple2>>::type
64  {
65  return std::tuple_cat(rem_in_tuple<I>::get(t1),
67  }
68 
70 
71  template <typename Lhs, typename Rhs, size_t I, size_t J>
72  class composer
73  {
74  static_assert(Lhs::element_type::context_t::is_lat,
75  "requires labels_are_tuples");
76  static_assert(Rhs::element_type::context_t::is_lat,
77  "requires labels_are_tuples");
78  public:
79  using clhs_t = Lhs;
80  using crhs_t = Rhs;
85  using I_labelset_t = typename l_labelset_t::template valueset_t<I>;
86  using J_labelset_t = typename r_labelset_t::template valueset_t<J>;
89 
95 
98 
100  using pair_state_t = std::pair<state_t,state_t>;
101 
102  composer(const Lhs& lhs, const Rhs& rhs)
103  : lhs_(lhs),
104  rhs_(rhs),
105  output_(make_mutable_automaton(make_context_(lhs, rhs)))
106  {}
107 
109  const r_labelset_t& rl)
110  {
111  return {concat_and_remove<I,J>(ll.sets(),rl.sets())};
112  }
113 
114  static context_t
115  make_context_(const Lhs& lhs, const Rhs& rhs)
116  {
117  return {make_labelset_(*lhs->context().labelset(), *rhs->context().labelset()),
118  join(*lhs->weightset(), *rhs->weightset())};
119  }
120 
122  {
123  state_t res;
124  auto i = map_.find(ps);
125  if (i == std::end(map_))
126  {
127  res = output_->add_state();
128  map_[ps] = res;
129  todo_.push(ps);
130  }
131  else
132  res = i->second;
133  return res;
134  }
135 
138  {
139  pair_state_t ps{lhs_->pre(),rhs_->pre()};
140  map_[ps] = output_->pre();
141  todo_.push(ps);
142  map_[std::make_pair(lhs_->post(),rhs_->post())] = output_->post();
143  const auto& ws = *output_->context().weightset();
144  while (!todo_.empty())
145  {
146  ps = todo_.top();
147  todo_.pop();
148  state_t src = state(ps);
149  auto it1 = lhs_->all_out(ps.first).begin();
150  auto end1 = lhs_->all_out(ps.first).end();
151  if(it1 == end1)
152  continue;
153  if(is_epsilon<I_labelset_t>(std::get<I>(lhs_->label_of(*it1))))
154  for(auto tr:lhs_->all_out(ps.first)) {
155  state_t q = lhs_->dst_of(tr);
156  state_t dst = state(std::make_pair(q, ps.second));
157  output_->add_transition(src, dst,
158  std::tuple_cat(rem_in_tuple<I>::get(lhs_->label_of(tr)), get_epsilon<minusJ_labelset_t>()),
159  lhs_->weight_of(tr));
160  }
161  else {
162  auto it2 = rhs_->all_out(ps.second).begin();
163  auto end2 = rhs_->all_out(ps.second).end();
164  while(it2 != end2) {
165  const auto& tr2=*it2;
166  if(is_epsilon<J_labelset_t>(std::get<J>(rhs_->label_of(tr2)))) {
167  state_t q = rhs_->dst_of(tr2);
168  state_t dst = state(std::make_pair(ps.first, q));
169  output_->add_transition(src, dst,
170  std::tuple_cat(get_epsilon<minusI_labelset_t>(),rem_in_tuple<J>::get(rhs_->label_of(tr2))),
171  rhs_->weight_of(tr2));
172  ++it2;
173  }
174  else if(it1 == end1)
175  ++it2;
176  else if(I_labelset_t::less_than(std::get<I>(lhs_->label_of(*it1)),
177  std::get<J>(rhs_->label_of(tr2))))
178  ++it1;
179  else if(I_labelset_t::less_than(std::get<J>(rhs_->label_of(tr2)),
180  std::get<I>(lhs_->label_of(*it1))))
181  ++it2;
182  else {
183  auto begin1 = it1;
184  while(it2 != end2 && I_labelset_t::equals(std::get<I>(lhs_->label_of(*begin1)),
185  std::get<J>(rhs_->label_of(*it2)))) {
186  it1=begin1;
187  while(it1 != end1 &&I_labelset_t::equals(std::get<I>(lhs_->label_of(*it1)),
188  std::get<J>(rhs_->label_of(*it2)))) {
189  state_t q1 = lhs_->dst_of(*it1);
190  state_t q2 = rhs_->dst_of(*it2);
191  state_t dst = state(std::make_pair(q1, q2));
192  output_->add_transition(src, dst,
193  std::tuple_cat(rem_in_tuple<I>::get(lhs_->label_of(*it1)),
194  rem_in_tuple<J>::get(rhs_->label_of(*it2))),
195  ws.mul(lhs_->weight_of(*it1),rhs_->weight_of(*it2)));
196  ++it1;
197  }
198  ++it2;
199  }
200  }
201  }
202  }
203  }
204  return output_;
205  }
206 
207  void set_history() {
208  auto history = std::make_shared<tuple_history<std::tuple<Lhs,Rhs>>>(std::make_tuple(lhs_,rhs_));
209  output_->set_history(history);
210  for (const auto& p: map_)
211  history->add_state(p.second, p.first);
212  }
213 
214  private:
215  const Lhs& lhs_;
216  const Rhs& rhs_;
217  using label_t = typename labelset_t::value_t;
218  using weight_t = typename weightset_t::value_t;
219 
220  std::unordered_map<pair_state_t, state_t> map_;
221  std::stack<pair_state_t> todo_;
222 
223  automaton_t output_;
224  };
225  }
226 
227  /*--------------------------------.
228  | compose(automaton, automaton). |
229  `--------------------------------*/
252  template <size_t I, size_t J, typename TDC1, typename TDC2>
253  auto
254  composeIJ(TDC1& tdc1, TDC2& tdc2, bool keep_history=true)
256  {
257  auto l = outsplit<I>(tdc1, keep_history);
258  sort_tape<I>(l);
259  sort_tape<J>(tdc2);
261  auto r= compose.compose();
262  if(keep_history)
263  compose.set_history();
264  proper_here(r);
265  return r;
266  }
267 
280  template <typename TDC1, typename TDC2>
281  auto
282  compose(const TDC1& tdc1, const TDC2& tdc2, bool keep_history=true)
284  {
285  return composeIJ<1,0>(tdc1, tdc2, keep_history);
286  }
287 
300  template <typename Aut, typename Tdc>
301  auto
302  eval_tdc(const Aut& aut, const Tdc& tdc, bool keep_history=true)
303  -> decltype(projection<1>(tdc))
304  {
305  auto l = partial_identity<1>(aut,keep_history);
306  auto r = composeIJ<0,0>(l, tdc, keep_history);
307  return projection<0>(r,keep_history);
308  }
309 
310 }}//end of ns awali::stc
311 
312 
313 #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:73
weightset_t_of< Lhs > l_weightset_t
Definition: compose.hh:83
weightset_t_of< Rhs > r_weightset_t
Definition: compose.hh:84
typename rem_in_tupleset< r_labelset_t, J >::type minusJ_labelset_t
Definition: compose.hh:88
typename l_labelset_t::template valueset_t< I > I_labelset_t
Definition: compose.hh:85
mutable_automaton< context_t > automaton_t
The type of the resulting automaton.
Definition: compose.hh:97
std::pair< state_t, state_t > pair_state_t
Result state type.
Definition: compose.hh:100
static labelset_t make_labelset_(const l_labelset_t &ll, const r_labelset_t &rl)
Definition: compose.hh:108
labelset_t_of< Lhs > l_labelset_t
Definition: compose.hh:81
state_t state(const pair_state_t &ps)
Definition: compose.hh:121
Rhs crhs_t
Definition: compose.hh:80
typename rem_in_tupleset< l_labelset_t, I >::type minusI_labelset_t
Definition: compose.hh:87
Lhs clhs_t
Definition: compose.hh:79
automaton_t compose()
The (accessible part of the) product of lhs_ and rhs_.
Definition: compose.hh:137
labelset_t_of< Rhs > r_labelset_t
Definition: compose.hh:82
join_t< weightset_t_of< context_t_of< Lhs > >, weightset_t_of< context_t_of< Rhs > >> weightset_t
Definition: compose.hh:93
static context_t make_context_(const Lhs &lhs, const Rhs &rhs)
Definition: compose.hh:115
sttc::context< labelset_t, weightset_t > context_t
Definition: compose.hh:94
void set_history()
Definition: compose.hh:207
typename r_labelset_t::template valueset_t< J > J_labelset_t
Definition: compose.hh:86
composer(const Lhs &lhs, const Rhs &rhs)
Definition: compose.hh:102
typename concat_tupleset< minusI_labelset_t, minusJ_labelset_t >::type labelset_t
The type of context of the result.
Definition: compose.hh:91
The semiring of rational numbers.
Definition: q.hh:41
The semiring of floating Numbers.
Definition: r.hh:34
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:60
Definition: compose.hh:38
Definition: tupleset.hh:969
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:254
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:282
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:206
auto join(const ratexpset< Ctx1 > &a, const ratexpset< Ctx2 > &b) -> ratexpset< join_t< Ctx1, Ctx2 >>
The union of two ratexpsets.
Definition: ratexpset.hh:448
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:911
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:302
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:53
typename tuple_to_tupleset< typename rem_in_tuple< I >::template type< std::tuple< T... > >>::type type
Definition: compose.hh:50
Definition: tuple.hh:365