Awali
Another Weighted Automata library
standard.hh
Go to the documentation of this file.
1 // This file is part of Awali.
2 // Copyright 2016-2023 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_STANDARD_HH
18 # define AWALI_ALGOS_STANDARD_HH
19 
20 # include <set>
21 
22 #include <awali/sttc/algos/copy.hh>
25 #include <awali/sttc/ctx/fwd.hh>
26 #include <awali/sttc/ctx/traits.hh>
28 #include <awali/sttc/misc/raise.hh>
29 #include <awali/sttc/misc/set.hh>
30 
31 namespace awali { namespace sttc {
32 
33 
34  /*-------------------------.
35  | is_standard(automaton). |
36  `-------------------------*/
37 
38  template <typename Aut>
39  bool
40  is_standard(const Aut& a)
41  {
42  return
43  a->num_initials() == 1
44  && a->weightset()->is_one(a->weight_of(*(a->initial_transitions().begin())))
45  // No arrival on the initial state.
46  && a->in(a->dst_of(*(a->initial_transitions().begin()))).empty();
47  }
48 
49  /*----------------------.
50  | standard(automaton). |
51  `----------------------*/
52 
56  template <typename Aut>
57  void
58  standard_here(Aut& aut)
59  {
60  if (is_standard(aut))
61  return;
62  const auto& ws = *aut->weightset();
63  const auto& inits = aut->initial_transitions();
64  std::vector<transition_t> initials{begin(inits), end(inits)};
65 
66  // See TAF-Kit documentation for the implementation details.
67  //
68  // (i.a) Add a new state s...
69  auto ini = aut->add_state();
70  for (auto ti: initials)
71  {
72  // The initial state.
73  auto i = aut->dst_of(ti);
74  auto wi = aut->weight_of(ti);
75  for (auto t: aut->all_out(i))
76  aut->add_transition(ini, aut->dst_of(t), aut->label_of(t),
77  ws.mul(wi, aut->weight_of(t)));
78  aut->del_transition(ti);
79 
80  // (iv) Remove the former initial states of A that are the
81  // destination of no incoming transition.
82  if (aut->all_in(i).empty())
83  aut->del_state(i);
84  }
85  // (i.b) Make [state s] initial, with initial multiplicity equal
86  // to the unit of the multiplicity semiring.
87  aut->set_initial(ini);
88  }
89 
90  template <typename Aut>
91  Aut
92  standard(Aut& aut, bool keep_history=true) {
93  auto out = copy(aut, keep_history);
94  standard_here(out);
95  return out;
96  }
97 
98  /*-------------------.
99  | standard(ratexp). |
100  `-------------------*/
101 
102  namespace rat
103  {
108  template <typename Aut,
109  typename Context = context_t_of<Aut>>
111  : public Context::const_visitor
112  {
113  public:
114  using automaton_t = Aut;
115  using context_t = Context;
118 
119  using super_type = typename Context::const_visitor;
120  using history_t = std::shared_ptr<string_history>;
121 
122  constexpr static const char* me() { return "standard"; }
123 
124  standard_visitor(const context_t& ctx, bool keep_history)
125  : ws_(*ctx.weightset())
126  , history_(std::make_shared<string_history>())
127  , res_(make_shared_ptr<automaton_t>(ctx))
128  , keep_history_(keep_history)
129  {}
130 
132  operator()(const typename context_t::ratexp_t& v)
133  {
134  if(keep_history_)
135  res_->set_history(history_);
136  v->accept(*this);
137  res_->set_initial(initial_);
138  history_->add_state(initial_,"i");
139  return std::move(res_);
140  }
141 
147 
149  {
150  initial_ = res_->add_state();
151  }
152 
154  {
155  auto i = res_->add_state();
156  initial_ = i;
157  res_->set_final(i);
158  }
159 
161  {
162  auto i = res_->add_state();
163  auto f = res_->add_state();
164  initial_ = i;
165  res_->new_transition(i, f, e.value());
166  res_->set_final(f);
167  history_->add_state(f,std::to_string(++count));
168  }
169 
171  using states_t = std::set<state_t>;
172  states_t
174  {
175  states_t res;
176  for (auto t: res_->final_transitions())
177  res.insert(res_->src_of(t));
178  return res;
179  }
180 
182  {
183  states_t other_finals = finals();
184  e.head()->accept(*this);
185  state_t initial = initial_;
186  for (auto c: e.tail())
187  {
188  c->accept(*this);
189  for (auto t: res_->all_out(initial_))
190  // Not set_transition: for instance 'a*+a*' will make
191  // "initial" go twice to post().
192  res_->add_transition(initial,
193  res_->dst_of(t),
194  res_->label_of(t),
195  res_->weight_of(t));
196  res_->del_state(initial_);
197  }
198  initial_ = initial;
199  }
200 
202  {
203  // The set of the final states that were introduced in pending
204  // parts of the automaton (for instance if we are in the rhs
205  // of "a+bc", recording the final state for "a").
206  states_t other_finals = finals();
207 
208  // Traverse the first part of the product, handle left_weight.
209  e.head()->accept(*this);
210  state_t initial = initial_;
211 
212  // Then the remainder.
213  for (auto c: e.tail())
214  {
215  // The set of the current (left-hand side) final transitions.
216  auto ftr_ = res_->final_transitions();
217  // Store transitions by copy.
218  using transs_t = std::vector<transition_t>;
219  transs_t ftr{ begin(ftr_), end(ftr_) };
220 
221  // Visit the next member of the product.
222  c->accept(*this);
223  // Branch all the previously added final transitions to
224  // the successors of the new initial state.
225  for (auto t1: ftr)
226  if (!sttc::internal::has(other_finals, res_->src_of(t1)))
227  {
228  // Remove the previous final transition first, as we
229  // might add a final transition for the same state
230  // later.
231  //
232  // For instance on "{2}a+({3}\e+{5}a)", the final
233  // state s1 of {2}a will be made final thanks to
234  // {3}\e. So if we compute the new transitions from
235  // s1 and then remove t1, we will have removed the
236  // fact that s1 is final thanks to {3}\e.
237  //
238  // Besides, s1 will become final with weight {3}, which
239  // might interfere with {5}a too.
240  auto s1 = res_->src_of(t1);
241  auto w1 = res_->weight_of(t1);
242  res_->del_transition(t1);
243  for (auto t2: res_->all_out(initial_))
244  res_->set_transition(s1,
245  res_->dst_of(t2),
246  res_->label_of(t2),
247  ws_.mul(w1, res_->weight_of(t2)));
248  }
249  res_->del_state(initial_);
250  }
251  initial_ = initial;
252  }
253 
254  // See star_here().
256  {
257  states_t other_finals = finals();
258  e.sub()->accept(*this);
259  // The "final weight of the initial state", starred.
260  weight_t w = ws_.star(res_->get_final_weight(initial_));
261  // Branch all the final states (but initial) to the successors
262  // of initial.
263  for (auto ti: res_->out(initial_))
264  {
265  res_->lmul_weight(ti, w);
266  for (auto tf: res_->final_transitions())
267  if (res_->src_of(tf) != initial_
268  && !sttc::internal::has(other_finals, res_->src_of(tf)))
269  // Note that the weight of ti has already been
270  // multiplied, on the left, by w.
271  //
272  // Not set_transition, as for instance with "a**", the
273  // second star modifies many existing transitions.
274  res_->add_transition
275  (res_->src_of(tf),
276  res_->dst_of(ti),
277  res_->label_of(ti),
278  ws_.mul(res_->weight_of(tf), res_->weight_of(ti)));
279  }
280  for (auto tf: res_->final_transitions())
281  if (!sttc::internal::has(other_finals, res_->src_of(tf)))
282  res_->rmul_weight(tf, w);
283  res_->set_final(initial_, w);
284  }
285 
287  {
288  states_t other_finals = finals();
289  e.sub()->accept(*this);
290  // The "final weight of the initial state", starred.
291  weight_t we = res_->get_final_weight(initial_);
292  weight_t w = ws_.star(we);
293  // Branch all the final states (but initial) to the successors
294  // of initial.
295  for (auto ti: res_->out(initial_))
296  {
297  res_->lmul_weight(ti, w);
298  for (auto tf: res_->final_transitions())
299  if (res_->src_of(tf) != initial_
300  && !sttc::internal::has(other_finals, res_->src_of(tf)))
301  // Note that the weight of ti has already been
302  // multiplied, on the left, by w.
303  //
304  // Not set_transition, as for instance with "a**", the
305  // second star modifies many existing transitions.
306  res_->add_transition
307  (res_->src_of(tf),
308  res_->dst_of(ti),
309  res_->label_of(ti),
310  ws_.mul(res_->weight_of(tf), res_->weight_of(ti)));
311  }
312  for (auto tf: res_->final_transitions())
313  if (!sttc::internal::has(other_finals, res_->src_of(tf)))
314  res_->rmul_weight(tf, w);
315  res_->set_final(initial_, ws_.plus(we));
316  }
317 
319  {
320  e.sub()->accept(*this);
321  res_->add_final(initial_, ws_.one());
322  }
323 
325  {
326  e.sub()->accept(*this);
327  for (auto t: res_->all_out(initial_))
328  res_->lmul_weight(t, e.weight());
329  }
330 
332  {
333  states_t other_finals = finals();
334  e.sub()->accept(*this);
335  for (auto t: res_->final_transitions())
336  if (! sttc::internal::has(other_finals, res_->src_of(t)))
337  res_->rmul_weight(t, e.weight());
338  }
339 
340  private:
341  const weightset_t& ws_;
342  automaton_t res_;
343  state_t initial_ = automaton_t::element_type::null_state();
344  history_t history_;
345  bool keep_history_;
346  unsigned count = 0;
347  };
348 
349  } // rat::
350 
351  /* @brief Convert a ratexp to a standard automaton.
352  *
353  * @tparam Aut static type of the generated automaton
354  * @tparam Context static type of the context of the generated automaton
355  * @param ctx the context of the generated automaton
356  * @param exp the rational expression
357  * @param keep_history (optional) if `true` (default value), the states are stamped with the position
358  * @return the standard automaton
359  */
360  template <typename Aut,
361  typename Context = context_t_of<Aut>>
362  Aut
363  standard(const Context& ctx, const typename Context::ratexp_t& e, bool keep_history=true)
364  {
366  return standard(e);
367  }
368 
369  /* @brief Convert a ratexp to a standard automaton.
370  *
371  * @tparam RatExpSet type of the context of the rational expression
372  * @param rs the context of the rational expression
373  * @param exp the rational expression
374  * @param keep_history (optional) if `true` (default value), the states are stamped with the position
375  * @return the standard automaton
376  */
377  template <typename RatExpSet>
378  inline
379  mutable_automaton<typename RatExpSet::context_t>
380  standard(const RatExpSet& rs, const typename RatExpSet::ratexp_t& e, bool keep_history=true)
381  {
382  rat::standard_visitor<mutable_automaton<typename RatExpSet::context_t>, typename RatExpSet::context_t> standard{rs.context(), keep_history};
383  return standard(e);
384  }
385 
386 
387  }}//end of ns awali::stc
388 
389 #endif // !AWALI_ALGOS_STANDARD_HH
The semiring of complex numbers.
Definition: c.hh:44
Definition: ratexp.hh:280
Definition: ratexp.hh:262
Convert a ratexp to a standard automaton.
Definition: standard.hh:112
weight_t_of< context_t > weight_t
Definition: standard.hh:117
constexpr static const char * me()
Definition: standard.hh:122
AWALI_RAT_VISIT(atom, e)
Definition: standard.hh:160
AWALI_RAT_VISIT(plus, e)
Definition: standard.hh:286
AWALI_RAT_VISIT(one,)
Definition: standard.hh:153
AWALI_RAT_VISIT(rweight, e)
Definition: standard.hh:331
AWALI_RAT_VISIT(star, e)
Definition: standard.hh:255
AWALI_RAT_VISIT(sum, e)
Definition: standard.hh:181
Context context_t
Definition: standard.hh:115
AWALI_RAT_VISIT(maybe, e)
Definition: standard.hh:318
standard_visitor(const context_t &ctx, bool keep_history)
Definition: standard.hh:124
typename Context::const_visitor super_type
Definition: standard.hh:119
AWALI_RAT_VISIT(lweight, e)
Definition: standard.hh:324
automaton_t operator()(const typename context_t::ratexp_t &v)
Definition: standard.hh:132
weightset_t_of< context_t > weightset_t
Definition: standard.hh:116
std::shared_ptr< string_history > history_t
Definition: standard.hh:120
AWALI_RAT_VISIT(zero,)
Definition: standard.hh:148
states_t finals()
Definition: standard.hh:173
AWALI_RAT_VISIT(prod, e)
Definition: standard.hh:201
std::set< state_t > states_t
The current set of final states.
Definition: standard.hh:171
Aut automaton_t
Definition: standard.hh:114
Definition: ratexp.hh:176
An inner node with multiple children.
Definition: ratexp.hh:115
An inner node implementing a weight.
Definition: ratexp.hh:208
Definition: string_history.hh:29
weightset_description weightset(const std::string &k)
bool has(const std::map< Key, Value, Compare, Alloc > &s, const Key &e)
Definition: map.hh:53
std::string to_string(identities i)
bool is_standard(const Aut &a)
Definition: standard.hh:40
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:29
typename internal::weight_t_of_impl< internal::base_t< ValueSet > >::type weight_t_of
Helper to retrieve the type of the weights of a value set.
Definition: traits.hh:81
Aut standard(Aut &aut, bool keep_history=true)
Definition: standard.hh:92
AutOut copy(const AutIn &input, Pred keep_state, bool keep_history=true, bool transpose=false)
A copy of input keeping only its states that are accepted by keep_state.
Definition: copy.hh:189
void standard_here(Aut &aut)
Turn aut into a standard automaton.
Definition: standard.hh:58
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
#define AWALI_RAT_UNSUPPORTED(Type)
Definition: visitor.hh:75