Vcsn  2.3a
Be Rational
efsm.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <algorithm>
4 #include <iostream>
5 
6 #include <boost/range/algorithm/sort.hpp>
7 
8 #include <vcsn/algos/grail.hh> // printer
9 #include <vcsn/dyn/fwd.hh>
10 #include <vcsn/labelset/fwd.hh>
11 #include <vcsn/misc/escape.hh>
12 #include <vcsn/misc/getargs.hh>
13 
14 namespace vcsn
15 {
16 
17  /*--------------------------.
18  | efsm(automaton, stream). |
19  `--------------------------*/
20  namespace detail
21  {
27  template <Automaton Aut>
28  class efsmer: public printer<Aut>
29  {
30  protected:
31  using automaton_t = Aut;
33 
34  using label_t = typename super_t::label_t;
35  using state_t = typename super_t::state_t;
37 
38  using super_t::os_;
39  using super_t::aut_;
40  using super_t::ls_;
41  using super_t::ws_;
43 
44  public:
45  using super_t::super_t;
46 
48  void operator()()
49  {
50  // Get it before, as it could raise an invalid argument error during
51  // the outputting.
52  auto arc_type = arc_type_();
53 
54  os_ <<
55  "#! /bin/sh\n"
56  "\n"
57  "me=$(basename \"$0\")\n"
58  "medir=$(mktemp -d \"/tmp/$me.XXXXXX\") || exit 1\n"
59  "\n";
60 
61  os_ <<
62  "arc_type=" << arc_type << "\n"
63  "\n";
64 
65  // Provide the symbols first, as when reading EFSM, knowing
66  // how \e is represented will help reading the transitions.
67  print_symbols_();
68 
69  os_ <<
70  "cat >$medir/transitions.fsm <<\\EOFSM";
72  os_ <<
73  "\n"
74  "EOFSM\n"
75  "\n"
76 
77  // Some OpenFST tools seem to require an output-symbol list,
78  // even for acceptors. While fstrmepsilon perfectly works
79  // with just the isymbols, fstintersect (equivalent to our
80  // conjunction) for instance, seems to require the osymbols;
81  // this seems to be due to the fact that Open FST bases its
82  // implementation of intersect on its (transducer)
83  // composition.
84  "fstcompile" << (is_transducer_ ? "" : " --acceptor") << " \\\n"
85  " --arc_type=$arc_type \\\n"
86  " --keep_isymbols --isymbols=" << isymbols_ << " \\\n"
87  " --keep_osymbols --osymbols=" << osymbols_ << " \\\n"
88  " $medir/transitions.fsm \"$@\"\n"
89  "sta=$?\n"
90  "\n"
91  "rm -rf $medir\n"
92  "exit $sta" // No final \n.
93  ;
94  }
95 
96  private:
98  std::string arc_type_() const
99  {
100  static const auto map = getarg<std::string>
101  {
102  "weightset",
103  {
104  {"b", "standard"},
105  {"zmin", "standard"},
106  {"rmin", "standard"},
107  {"nmin", "standard"},
108  {"log", "log64"},
109  }
110  };
111  return map[ws_.sname()];
112  }
113 
114  template <typename LS>
115  void print_label_(const LS& ls, const typename LS::value_t& l) const
116  {
117  if (ls.is_special(l))
118  os_ << "\\e";
119  else
120  ls.print(l, os_, format::raw);
121  }
122 
124  template <typename Label>
125  void print_label_(const Label& l, std::false_type) const
126  {
127  print_label_(ls_, l);
128  }
129 
131  template <typename Label>
132  void print_label_(const Label& l, std::true_type) const
133  {
134  print_label_(ls_.template set<0>(), std::get<0>(l));
135  os_ << '\t';
136  print_label_(ls_.template set<1>(), std::get<1>(l));
137  }
138 
139  void print_transition_(const transition_t t) const override
140  {
141  // Don't output "pre", but an integer.
142  // Previously, a very large unsigned integer was used. This introduced
143  // an error in newer version of OpenFST, which read it as if it were a
144  // negative number. Instead, the state number immediately after
145  // the highest state number is used. There is a shift of 2 when printing
146  // states number because of pre/post.
147  if (aut_->src_of(t) == aut_->pre())
148  os_ << states_size(aut_) - 2;
149  else
150  aut_->print_state(aut_->src_of(t), os_);
151  if (aut_->dst_of(t) != aut_->post())
152  {
153  os_ << '\t';
154  aut_->print_state(aut_->dst_of(t), os_);
155  os_ << '\t';
156  print_label_(aut_->label_of(t), is_transducer_);
157  }
158 
159  if (ws_.show_one() || !ws_.is_one(aut_->weight_of(t)))
160  {
161  os_ << '\t';
162  ws_.print(aut_->weight_of(t), os_);
163  }
164  }
165 
168  {
169  // FSM format supports a single initial state with one as
170  // weight. This requires, when we have several initial
171  // states or an non, to "exhibit" pre() and spontaneous transitions.
172  // Avoid this when possible.
173  auto inis = initial_transitions(aut_);
174  if (inis.size() != 1
175  || !ws_.is_one(aut_->weight_of(inis.front())))
176  for (auto t : inis)
177  {
178  os_ << '\n';
180  }
181 
182  // We _must_ start by the initial state.
183  {
184  std::vector<state_t> states(std::begin(aut_->states()),
185  std::end(aut_->states()));
186  boost::sort(states,
187  [this](state_t l, state_t r)
188  {
189  return (std::forward_as_tuple(!aut_->is_initial(l), l)
190  < std::forward_as_tuple(!aut_->is_initial(r), r));
191  });
192  for (auto s: states)
193  this->print_state_(s);
194  }
195  for (auto t : final_transitions(aut_))
196  {
197  os_ << '\n';
199  }
200  }
201 
214  template <typename LabelSet, typename Labels, typename GetLabel>
215  auto add_alphabet_(const LabelSet& ls, Labels& labels, GetLabel get_label)
216  -> std::enable_if_t<has_generators_mem_fn<LabelSet>{}>
217  {
218  for (auto l : ls.generators())
219  labels.insert(get_label(ls.value(l)));
220  }
221 
225  template <typename LabelSet, typename Labels, typename GetLabel>
226  auto add_alphabet_(const LabelSet&, Labels&, GetLabel)
227  -> std::enable_if_t<!has_generators_mem_fn<LabelSet>{}>
228  {}
229 
254  template <typename LabelSet, typename GetLabel>
255  void print_symbols_(const std::string& name,
256  const LabelSet& ls,
257  GetLabel get_label)
258  {
259  // The labels we declare.
260  using labelset_t = LabelSet;
261  using label_t = typename labelset_t::value_t;
262 
263  auto labels = std::set<label_t, vcsn::less<labelset_t>>{};
264  // If there is an alphabet, include it, to preserve the
265  // context in round trips.
266  add_alphabet_(*aut_->labelset(), labels, get_label);
267  // In any case, insert all our labels.
268  for (auto t : transitions(aut_))
269  labels.insert(get_label(aut_->label_of(t)));
270 
271  // Sorted per label name, which is fine, and deterministic.
272  // Start with special/epsilon. Show it as \e.
273  os_ <<
274  "cat >" << name << " <<\\EOFSM\n"
275  "\\e\t0\n";
276  size_t num = 0;
277  for (const auto& l: labels)
278  if (!ls.is_one(l))
279  {
280  ls.print(l, os_, format::raw);
281  os_ << '\t' << ++num << '\n';
282  }
283  os_ <<
284  "EOFSM\n"
285  "\n";
286  }
287 
289  template <typename>
290  void
291  print_symbols_impl_(std::false_type)
292  {
293  print_symbols_(isymbols_,
294  ls_,
295  [](label_t l) { return l; });
296  }
297 
299  template <typename>
300  void
301  print_symbols_impl_(std::true_type)
302  {
303  print_symbols_(isymbols_,
304  ls_.template set<0>(),
305  [](const label_t& l) { return std::get<0>(l); });
306  print_symbols_(osymbols_,
307  ls_.template set<1>(),
308  [](const label_t& l) { return std::get<1>(l); });
309  }
310 
311  void
312  print_symbols_()
313  {
314  print_symbols_impl_<automaton_t>(is_transducer_);
315  }
316 
318  const char* isymbols_ =
319  is_transducer_ ? "$medir/isymbols.txt" : "$medir/symbols.txt";
321  const char* osymbols_ =
322  is_transducer_ ? "$medir/osymbols.txt" : "$medir/symbols.txt";
323  };
324  }
325 
326 
330  template <Automaton Aut>
331  std::ostream&
332  efsm(const Aut& aut, std::ostream& out = std::cout)
333  {
334  auto efsm = detail::efsmer<Aut>{aut, out};
335  efsm();
336  return out;
337  }
338 }
size_t states_size(const Aut &aut)
The largest state number, plus one.
Definition: automaton.hh:39
const char * osymbols_
File name for output tape symbols.
Definition: efsm.hh:321
state_t_of< automaton_t > state_t
Definition: printer.hh:50
Print as is. For instance, don't try to escape labels.
Definition: format.hh:24
auto add_alphabet_(const LabelSet &, Labels &, GetLabel) -> std::enable_if_t<!has_generators_mem_fn< LabelSet >
Fill ls with the letters.
Definition: efsm.hh:226
auto map(const std::tuple< Ts... > &ts, Fun f) -> decltype(map_tuple_(f, ts, make_index_sequence< sizeof...(Ts)>()))
Map a function on a tuple, return tuple of the results.
Definition: tuple.hh:177
Print automaton to EFSM format, based on FSM format.
Definition: efsm.hh:28
void operator()()
Actually output aut_ on os_.
Definition: efsm.hh:48
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:84
void print_label_(const Label &l, std::true_type) const
Two-tape automaton.
Definition: efsm.hh:132
void print_label_(const LS &ls, const typename LS::value_t &l) const
Definition: efsm.hh:115
Definition: a-star.hh:8
transition_t_of< automaton_t > transition_t
Definition: printer.hh:55
std::ostream & os_
Output stream.
Definition: printer.hh:135
auto sort(const Aut &a) -> permutation_automaton< Aut >
Definition: sort.hh:161
const is_transducer_t is_transducer_
Definition: printer.hh:147
auto transitions(const Aut &aut) -> decltype(all_transitions(aut, is_special_t< Aut >
All the transition indexes between visible states.
Definition: automaton.hh:246
void print_state_(const state_t s)
Output transitions, sorted lexicographically on (Label, Dest).
Definition: printer.hh:81
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
std::string arc_type_() const
The OpenFST name that corresponds to our weightset.
Definition: efsm.hh:98
typename super_t::label_t label_t
Definition: efsm.hh:34
Factor common bits in automaton formatting.
Definition: printer.hh:37
void print_label_(const Label &l, std::false_type) const
Acceptor.
Definition: efsm.hh:125
void print_transition_(const transition_t t) const override
Output the transition t.
Definition: efsm.hh:139
automaton_t aut_
The automaton we have to output.
Definition: printer.hh:133
std::ostream & efsm(const Aut &aut, std::ostream &out=std::cout)
Print automaton to EFSM format, based on FSM format.
Definition: efsm.hh:332
auto initial_transitions(const Aut &aut) -> decltype(aut->all_out(aut->pre()))
Indexes of transitions to (visible) initial states.
Definition: automaton.hh:165
A mapping from strings to Values.
Definition: getargs.hh:33
void print_transitions_()
Output all the transitions, and final states.
Definition: efsm.hh:167
auto add_alphabet_(const LabelSet &ls, Labels &labels, GetLabel get_label) -> std::enable_if_t< has_generators_mem_fn< LabelSet >
Fill labels with the gensets of ls.
Definition: efsm.hh:215
auto final_transitions(const Aut &aut) -> decltype(aut->all_in(aut->post()))
Indexes of transitions from (visible) final states.
Definition: automaton.hh:176
const weightset_t & ws_
Short-hand to the weightset.
Definition: printer.hh:139
label_t_of< automaton_t > label_t
Definition: printer.hh:54
const labelset_t_of< automaton_t > & ls_
Short-hand to the labelset.
Definition: printer.hh:137
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46