Vcsn  2.0
Be Rational
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
mutable-automaton.hh
Go to the documentation of this file.
1 #ifndef VCSN_CORE_MUTABLE_AUTOMATON_HH
2 # define VCSN_CORE_MUTABLE_AUTOMATON_HH
3 
4 # include <algorithm>
5 # include <cassert>
6 # include <vector>
7 
8 # include <boost/range/irange.hpp>
9 
10 # include <vcsn/core/crange.hh>
11 # include <vcsn/core/fwd.hh>
12 # include <vcsn/core/transition.hh>
13 # include <vcsn/ctx/context.hh>
14 # include <vcsn/ctx/traits.hh>
15 # include <vcsn/misc/memory.hh>
16 
17 namespace vcsn
18 {
19  namespace detail
20  {
21  template <typename Context>
22  class mutable_automaton_impl
23  {
24  public:
25  using context_t = Context;
31  using kind_t = typename context_t::kind_t;
32 
33  using labelset_ptr = typename context_t::labelset_ptr;
34  using weightset_ptr = typename context_t::weightset_ptr;
35 
37  using state_t = unsigned;
39  using transition_t = unsigned;
41  using label_t = typename labelset_t::value_t;
43  using weight_t = typename weightset_t::value_t;
44 
45  protected:
48 
51 
53  using tr_store_t = std::vector<stored_transition_t>;
55  using tr_cont_t = std::vector<transition_t>;
56 
59  {
62  };
63 
65  using st_store_t = std::vector<stored_state_t>;
66 
68  using free_store_t = std::vector<unsigned>;
69 
78 
79  public:
80  mutable_automaton_impl() = delete;
83  : ctx_{ctx}
84  , states_{2}
85  , prepost_label_(ctx.labelset()->special())
86  {}
87 
89  : ctx_(that.ctx_)
91  {
92  *this = std::move(that);
93  }
94 
96  {
97  if (this != &that)
98  {
99  ctx_ = std::move(that.ctx_);
100  prepost_label_ = std::move(that.prepost_label_);
101  std::swap(states_, that.states_);
102  std::swap(states_fs_, that.states_fs_);
103  std::swap(transitions_, that.transitions_);
104  std::swap(transitions_fs_, that.transitions_fs_);
105  }
106  return *this;
107  }
108 
109  // Related sets
111 
112  static std::string sname()
113  {
114  return "mutable_automaton<" + context_t::sname() + ">";
115  }
116 
117  std::string vname(bool full = true) const
118  {
119  return "mutable_automaton<" + context().vname(full) + ">";
120  }
121 
122  const context_t& context() const { return ctx_; }
123  const weightset_ptr& weightset() const { return ctx_.weightset(); }
124  const labelset_ptr& labelset() const { return ctx_.labelset(); }
125 
126  // Special states and transitions
128 
129  // pseudo-initial and final states.
130  // The code below assumes that pre() and post() are the first
131  // two states of the automaton. In other words, all other states
132  // have greater numbers. We also assume that pre()<post().
133  static constexpr state_t pre() { return 0U; }
134  static constexpr state_t post() { return 1U; }
136  static constexpr state_t null_state() { return -1U; }
138  static constexpr transition_t null_transition() { return -1U; }
139 
141  {
142  return prepost_label_;
143  }
144 
145  // Statistics
147 
148  size_t num_all_states() const { return states_.size() - states_fs_.size(); }
149  size_t num_states() const { return num_all_states() - 2; }
150  size_t num_initials() const { return states_[pre()].succ.size(); }
151  size_t num_finals() const { return states_[post()].pred.size(); }
152  size_t num_transitions() const
153  {
154  return (transitions_.size()
155  - transitions_fs_.size() - num_initials() - num_finals());
156  }
157 
158  // Queries on states
160 
161  bool
163  {
164  // Any number outside our container is not a state.
165  // (This includes "null_state()".)
166  if (s >= states_.size())
167  return false;
168  const stored_state_t& ss = states_[s];
169 
170  // Erased states have 'invalid' as their first successor.
171  return ss.succ.empty() || ss.succ.front() != null_transition();
172  }
173 
174  bool
176  {
177  return has_transition(pre(), s, prepost_label_);
178  }
179 
180  bool
181  is_final(state_t s) const
182  {
183  return has_transition(s, post(), prepost_label_);
184  }
185 
186  ATTRIBUTE_PURE
187  weight_t
189  {
191  if (t == null_transition())
192  return weightset()->zero();
193  else
194  return weight_of(t);
195  }
196 
197  ATTRIBUTE_PURE
198  weight_t
200  {
202  if (t == null_transition())
203  return weightset()->zero();
204  else
205  return weight_of(t);
206  }
207 
208  // Queries on transitions
210 
213  {
214  assert(has_state(src));
215  assert(has_state(dst));
216  const tr_cont_t& succ = states_[src].succ;
217  const tr_cont_t& pred = states_[dst].pred;
218  const auto& ls = *this->labelset();
219  if (succ.size() <= pred.size())
220  {
221  auto i =
222  std::find_if(begin(succ), end(succ),
223  [this,l,ls,dst] (transition_t t) -> bool
224  {
225  return (dst_of(t) == dst
226  && ls.equals(label_of(t), l));
227  });
228  if (i != end(succ))
229  return *i;
230  }
231  else
232  {
233  auto i =
234  std::find_if(begin(pred), end(pred),
235  [this,l,ls,src] (transition_t t) -> bool
236  {
237  return (src_of(t) == src
238  && ls.equals(label_of(t), l));
239  });
240  if (i != end(pred))
241  return *i;
242  }
243  return null_transition();
244  }
245 
246  bool
248  {
249  return get_transition(src, dst, l) != null_transition();
250  }
251 
252  bool
254  {
255  // Any number outside our container is not a transition.
256  // (This includes "null_transition()".)
257  if (t >= transitions_.size())
258  return false;
259 
260  // Erased transition have invalid source state.
261  return transitions_[t].src != null_state();
262  }
263 
264  state_t src_of(transition_t t) const { return transitions_[t].src; }
265  state_t dst_of(transition_t t) const { return transitions_[t].dst; }
267  {
268  return transitions_[t].get_label();
269  }
270 
272  {
273  return transitions_[t].get_weight();
274  }
275 
276  // Edition of states
278 
279  protected:
281  void
283  {
285  auto& succ = states_[st.src].succ;
286  auto tsucc = std::find(succ.begin(), succ.end(), t);
287  assert(tsucc != succ.end());
288  *tsucc = std::move(succ.back());
289  succ.pop_back();
290  }
291 
293  void
295  {
297  auto& pred = states_[st.dst].pred;
298  auto tpred = std::find(pred.begin(), pred.end(), t);
299  assert(tpred != pred.end());
300  *tpred = std::move(pred.back());
301  pred.pop_back();
302  }
303 
304  void
305  del_transition_container(tr_cont_t& tc, bool from_succ)
306  {
307  for (auto t: tc)
308  {
309  if (from_succ)
311  else
313  transitions_[t].src = null_state();
314  }
315  transitions_fs_.insert(transitions_fs_.end(), tc.begin(), tc.end());
316  tc.clear();
317  }
318 
319  public:
320  state_t
322  {
323  state_t s;
324  if (states_fs_.empty())
325  {
326  s = states_.size();
327  states_.resize(s + 1);
328  }
329  else
330  {
331  s = states_fs_.back();
332  states_fs_.pop_back();
333  }
334  stored_state_t& ss = states_[s];
335  // De-invalidate this state: remove the invalid transition.
336  ss.succ.clear();
337  return s;
338  }
339 
340  std::ostream&
341  print_state(state_t s, std::ostream& o) const
342  {
343  return o << s - 2;
344  }
345 
346  std::ostream&
347  print_state_name(state_t s, std::ostream& o,
348  const std::string& = "text",
349  bool = true) const
350  {
351  return print_state(s, o);
352  }
353 
354  static constexpr bool
356  {
357  return false;
358  }
359 
360  void
362  {
363  assert(has_state(s));
364  assert(s > post()); // Cannot erase pre() and post().
365  stored_state_t& ss = states_[s];
366  del_transition_container(ss.pred, false);
367  del_transition_container(ss.succ, true);
368  ss.succ.emplace_back(null_transition()); // So has_state() can work.
369  states_fs_.emplace_back(s);
370  }
371 
372  void
374  {
376  }
377 
378  void
380  {
381  set_initial(s, weightset()->one());
382  }
383 
384  weight_t
386  {
387  return add_transition(pre(), s, prepost_label_, w);
388  }
389 
390  void
392  {
393  set_initial(s, weightset()->zero());
394  }
395 
396  void
398  {
400  }
401 
402  void
404  {
405  set_final(s, weightset()->one());
406  }
407 
408  weight_t
410  {
411  return add_transition(s, post(), prepost_label_, w);
412  }
413 
414  void
416  {
417  set_final(s, weightset()->zero());
418  }
419 
420  // Edition of transitions
422 
423  void
425  {
426  assert(has_transition(t));
427  // Remove transition from source and destination.
430  // Actually erase the transition.
431  transitions_[t].src = null_state();
432  transitions_fs_.emplace_back(t);
433  }
434 
436  void
438  {
439  transition_t t = get_transition(src, dst, l);
440  if (t != null_transition())
441  del_transition(t);
442  }
443 
445  void
447  {
448  // Make a copy of the transition indexes, as the iterators are
449  // invalidated by del_transition(t).
450  auto ts = outin(s, d);
451  for (auto t: tr_cont_t{std::begin(ts), std::end(ts)})
452  del_transition(t);
453  }
454 
467  {
468  assert(!has_transition(src, dst, l));
469  if (weightset()->is_zero(w))
470  return null_transition();
471  else
472  {
473  transition_t t;
474  if (transitions_fs_.empty())
475  {
476  t = transitions_.size();
477  transitions_.resize(t + 1);
478  }
479  else
480  {
481  t = transitions_fs_.back();
482  transitions_fs_.pop_back();
483  }
485  st.src = src;
486  st.dst = dst;
487  // FIXME: When src == pre() || dst == post(), label must be empty.
488  st.set_label(l);
489  st.set_weight(w);
490  states_[src].succ.emplace_back(t);
491  states_[dst].pred.emplace_back(t);
492  return t;
493  }
494  }
495 
509  template <typename A>
512  const A& aut, typename A::element_type::transition_t t,
513  bool transpose = false)
514  {
515  auto l = aut->label_of(t);
516  auto w = aut->weight_of(t);
517  if (transpose)
518  {
519  l = aut->labelset()->transpose(l);
520  w = aut->weightset()->transpose(w);
521  }
522  return new_transition(src, dst,
523  labelset()->conv(*aut->labelset(), l),
524  weightset()->conv(*aut->weightset(), w));
525  }
526 
530  {
531  return new_transition(src, dst, l, weightset()->one());
532  }
533 
546  {
547  // It's illegal to connect pre() to post().
548  // FIXME: reenable except for labels_are_one.
549  // assert(src != pre() || dst != post());
550  // It's illegal to leave post().
551  assert(src != post());
552  // It's illegal to go to pre().
553  assert(dst != pre());
554 
555  transition_t t = get_transition(src, dst, l);
556  if (t == null_transition())
557  t = new_transition(src, dst, l, w);
558  else if (weightset()->is_zero(w))
559  {
560  del_transition(t);
561  t = null_transition();
562  }
563  else
564  {
566  st.set_label(l);
567  st.set_weight(w);
568  }
569  return t;
570  }
571 
575  {
576  return set_transition(src, dst, l, weightset()->one());
577  }
578 
589  weight_t
591  {
592  transition_t t = get_transition(src, dst, l);
593  if (t == null_transition())
594  new_transition(src, dst, l, w);
595  else
596  {
597  w = weightset()->add(weight_of(t), w);
598  set_weight(t, w);
599  }
600  return w;
601  }
602 
604  weight_t
606  {
607  return add_transition(src, dst, l, weightset()->one());
608  }
609 
621  template <typename A>
622  weight_t
624  const A& aut, typename A::element_type::transition_t t,
625  bool transpose = false)
626  {
627  auto l = aut->label_of(t);
628  auto w = aut->weight_of(t);
629  if (transpose)
630  {
631  l = aut->labelset()->transpose(l);
632  w = aut->weightset()->transpose(w);
633  }
634  return add_transition(src, dst,
635  labelset()->conv(*aut->labelset(), l),
636  weightset()->conv(*aut->weightset(), w));
637  }
638 
639  std::string
641  {
642  constexpr char langle = '<';
643  constexpr char rangle = '>';
644 
645  std::ostringstream o;
646  o << src_of(t)
647  << " -- "
648  << langle;
649  weightset()->print(weight_of(t), o)
650  << rangle;
651  labelset()->print(label_of(t), o)
652  << " --> "
653  << dst_of(t);
654  return o.str();
655  }
656 
657  weight_t
659  {
660  if (weightset()->is_zero(w))
661  del_transition(t);
662  else
663  transitions_[t].set_weight(w);
664  return w;
665  }
666 
667  weight_t
669  {
670  return set_weight(t, weightset()->add(weight_of(t), w));
671  }
672 
673  weight_t
675  {
676  return set_weight(t, weightset()->mul(w, weight_of(t)));
677  }
678 
679  weight_t
681  {
682  return set_weight(t, weightset()->mul(weight_of(t), w));
683  }
684 
685  // Iteration on states and transitions
687 
688  using states_output_t =
690 
691  protected:
694  template <typename Pred>
696  state_range(state_t b, state_t e, Pred pred) const
697  {
698  return
699  {boost::irange<state_t>(b, e),
700  [this,pred] (state_t s) -> bool
701  {
702  const stored_state_t& ss = states_[s];
703  return ((ss.succ.empty()
704  || ss.succ.front() != this->null_transition())
705  && pred(s));
706  }};
707  }
708 
712  {
713  return state_range(b, e, [](state_t) { return true; });
714  }
715 
716  public:
720  all_states() const { return state_range(0U, states_.size()); }
721 
724  template <typename Pred>
726  all_states(Pred pred) const
727  {
728  return state_range(0U, states_.size(), pred);
729  }
730 
734  states() const { return state_range(post() + 1, states_.size()); }
735 
736  using transitions_output_t =
738 
741  template <typename Pred>
743  all_transitions(Pred pred) const
744  {
745  return
746  {
747  boost::irange<transition_t>(0U, transitions_.size()),
748  [this,pred] (transition_t t)
749  {
750  return (src_of(t) != this->null_state()
751  && pred(t));
752  }
753  };
754  }
755 
759  {
760  return all_transitions([] (transition_t) { return true; });
761  }
762 
765  transitions() const
766  {
767  return all_transitions([this] (transition_t t)
768  {
769  return (src_of(t) != pre()
770  && dst_of(t) != post());
771  });
772  }
773 
777  {
778  return out(pre());
779  }
780 
784  {
785  return in(post());
786  }
787 
791  all_out(state_t s) const
792  {
793  assert(has_state(s));
794  return states_[s].succ;
795  }
796 
801  template <typename Pred>
803  all_out(state_t s, Pred pred) const
804  {
805  assert(has_state(s));
806  return {states_[s].succ, pred};
807  }
808 
812  out(state_t s) const
813  {
814  return all_out(s,
815  [this] (transition_t t)
816  { return dst_of(t) != post(); });
817  }
818 
822  out(state_t s, const label_t& l) const
823  {
824  return all_out(s,
825  [this,l] (transition_t t)
826  {
827  return labelset()->equals(label_of(t), l);
828  });
829  }
830 
834  all_in(state_t s) const
835  {
836  assert(has_state(s));
837  return states_[s].pred;
838  }
839 
844  template <typename Pred>
846  all_in(state_t s, Pred pred) const
847  {
848  assert(has_state(s));
849  return {states_[s].pred, pred};
850  }
851 
855  in(state_t s) const
856  {
857  return all_in(s,
858  [this] (transition_t t)
859  { return src_of(t) != pre(); });
860  }
861 
865  in(state_t s, const label_t& l) const
866  {
867  return all_in(s,
868  [this,l] (transition_t t)
869  {
870  return labelset()->equals(label_of(t), l);
871  });
872  }
873 
877  outin(state_t s, state_t d) const
878  {
879  return all_out(s,
880  [this,d] (transition_t t)
881  {
882  return dst_of(t) == d;
883  });
884  }
885  };
886  }
887 
888  template <typename Context>
889  mutable_automaton<Context>
890  make_mutable_automaton(const Context& ctx)
891  {
892  return make_shared_ptr<mutable_automaton<Context>>(ctx);
893  }
894 }
895 
896 #endif // !VCSN_CORE_MUTABLE_AUTOMATON_HH
weight_t add_transition(state_t src, state_t dst, label_t l)
Same as above, with weight one.
ATTRIBUTE_PURE weight_t get_final_weight(state_t s) const
ATTRIBUTE_PURE weight_t get_initial_weight(state_t s) const
transitions_output_t all_transitions(Pred pred) const
All the transition indexes between all states (including pre and post), that validate pred...
label_t prepost_label_
Label for initial and final transitions.
Restrict the interface of a container to begin/end.
Definition: crange.hh:13
mutable_automaton< Context > make_mutable_automaton(const Context &ctx)
bool has_transition(transition_t t) const
std::vector< unsigned > free_store_t
A list of unused indexes in the states/transitions tables.
states_output_t all_states(Pred pred) const
All states including pre()/post() that validate pred.
labelset_t_of< context_t > labelset_t
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
Definition: traits.hh:34
transitions_output_t transitions() const
All the transition indexes between visible states.
transition_t new_transition_copy(state_t src, state_t dst, const A &aut, typename A::element_type::transition_t t, bool transpose=false)
Copy the label of a transition between two states, creating a new transition.
label_t label_of(transition_t t) const
weight_t add_weight(transition_t t, weight_t w)
static constexpr state_t null_state()
Invalid state.
void set_weight(weight_t &k)
Definition: transition.hh:51
void del_transition_from_src(transition_t t)
Remove t from the outgoing transitions of the source state.
unsigned state_t
Lightweight state handle (or index).
container_filter_range< boost::integer_range< transition_t >> transitions_output_t
static constexpr transition_t null_transition()
Invalid transition.
typename context_t::kind_t kind_t
weight_t add_final(state_t s, weight_t w)
std::ostream & print_state_name(state_t s, std::ostream &o, const std::string &="text", bool=true) const
const context_t & context() const
std::string sname()
Definition: name.hh:31
variadic_mul_mixin< detail::b_impl > b
Definition: fwd.hh:38
bool has_transition(state_t src, state_t dst, label_t l) const
std::shared_ptr< detail::mutable_automaton_impl< Context >> mutable_automaton
Definition: fwd.hh:25
std::vector< transition_t > tr_cont_t
All the incoming/outgoing transition handles of a state.
container_filter_range< const tr_cont_t & > outin(state_t s, state_t d) const
Indexes of visible transitions from state s to state d.
auto conv(const ValueSet &vs, const std::string &str, Args &&...args) -> decltype(vs.conv(std::declval< std::istream & >(), std::forward< Args >(args)...))
Parse str via vs.conv.
Definition: stream.hh:29
mutable_automaton< context_t > automaton_nocv_t
The (shared pointer) type to use if we have to create an automaton of the same (underlying) type...
container_filter_range< const tr_cont_t & > out(state_t s, const label_t &l) const
Indexes of all transitions leaving state s on label l.
container_filter_range< boost::integer_range< state_t >> states_output_t
container_filter_range< const tr_cont_t & > all_in(state_t s, Pred pred) const
Indexes of transitions entering state s that validate the predicate.
weight_t weight_of(transition_t t) const
state_t src_of(transition_t t) const
std::vector< stored_transition_t > tr_store_t
All the automaton's transitions.
container_filter_range< const tr_cont_t & > initial_transitions() const
Indexes of transitions to visible initial states.
void del_transition(state_t src, state_t dst, label_t l)
Remove the transition (src, l, dst).
void del_transition(state_t s, state_t d)
Remove all the transitions between s and d.
void set_final(state_t s, weight_t w)
state_t dst_of(transition_t t) const
weightset_t_of< context_t > weightset_t
transition_t new_transition(state_t src, state_t dst, label_t l)
Same as above, with weight one.
mutable_automaton_impl(const context_t &ctx)
typename context_t::labelset_ptr labelset_ptr
mutable_automaton_impl & operator=(mutable_automaton_impl &&that)
typename context_t::weightset_ptr weightset_ptr
static constexpr bool state_has_name(state_t)
const labelset_ptr & labelset() const
container_filter_range< const tr_cont_t & > all_out(state_t s, Pred pred) const
Indexes of transitions leaving state s that validate the predicate.
container_filter_range< const tr_cont_t & > final_transitions() const
Indexes of transitions from visible final states.
transition_t set_transition(state_t src, state_t dst, label_t l)
Same as above, with unit weight.
const weightset_ptr & weightset() const
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:38
transition_t get_transition(state_t src, state_t dst, label_t l) const
mutable_automaton_impl(mutable_automaton_impl &&that)
container_filter_range< const tr_cont_t & > out(state_t s) const
Indexes of visible transitions leaving state s.
std::vector< stored_state_t > st_store_t
All the automaton's states.
states_output_t states() const
All states excluding pre()/post().
states_output_t all_states() const
All states including pre()/post().
states_output_t state_range(state_t b, state_t e, Pred pred) const
The range of state numbers in [b .
typename weightset_t::value_t weight_t
Transition weight.
weight_t add_initial(state_t s, weight_t w)
weight_t lmul_weight(transition_t t, weight_t w)
weight_t add_transition(state_t src, state_t dst, label_t l, weight_t w)
Add a transition between two states.
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:36
void del_transition_from_dst(transition_t t)
Remove t from the ingoing transition of the destination state.
Aut transpose(const transpose_automaton< Aut > &aut)
Definition: transpose.hh:230
container_range< const tr_cont_t & > all_in(state_t s) const
Indexes of all transitions arriving to state s.
container_range< const tr_cont_t & > all_out(state_t s) const
Indexes of all transitions leaving state s.
transition_t new_transition(state_t src, state_t dst, label_t l, weight_t w)
Create a transition between two states.
std::string vname(bool full=true) const
container_filter_range< const tr_cont_t & > in(state_t s, const label_t &l) const
Indexes of visible transitions arriving to state s on label l.
weight_t rmul_weight(transition_t t, weight_t w)
container_filter_range< const tr_cont_t & > in(state_t s) const
Indexes of visible transitions arriving to state s.
states_output_t state_range(state_t b, state_t e) const
The range of state numbers in [b .. e].
weight_t set_weight(transition_t t, weight_t w)
transition_t set_transition(state_t src, state_t dst, label_t l, weight_t w)
Set a transition between two states.
std::ostream & print_state(state_t s, std::ostream &o) const
void del_transition_container(tr_cont_t &tc, bool from_succ)
weight_t add_transition_copy(state_t src, state_t dst, const A &aut, typename A::element_type::transition_t t, bool transpose=false)
Add a transition between two states, copying the label from the given transition. ...
unsigned transition_t
Lightweight transition handle (or index).
transitions_output_t all_transitions() const
All the transition indexes between all states (including pre and post).
free_store_t transitions_fs_
Free indexes in transitions_.
typename labelset_t::value_t label_t
Transition label.
void set_initial(state_t s, weight_t w)
std::string format_transition(transition_t t) const
context_t ctx_
The algebraic type of this automaton.
free_store_t states_fs_
Free indexes in states_.
ATTRIBUTE_PURE auto find(const std::vector< T, Alloc > &s, const T &e) -> typename std::vector< T, Alloc >::const_iterator
Convenience wrapper around std::find.
Definition: vector.hh:66