Vcsn  2.2
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  {
23  template <typename LabelSet>
24  struct rank
25  {
26  static constexpr size_t value = 1;
27  };
28 
29  template <typename... LabelSet>
30  struct rank<tupleset<LabelSet...>>
31  {
32  static constexpr size_t value = sizeof...(LabelSet);
33  };
34 
40  template <Automaton Aut>
41  class efsmer: public printer<Aut>
42  {
43  protected:
44  using automaton_t = Aut;
46 
47  using label_t = typename super_t::label_t;
48  using state_t = typename super_t::state_t;
50 
51  using super_t::os_;
52  using super_t::aut_;
53  using super_t::ls_;
54  using super_t::ws_;
55 
56  public:
57  using super_t::super_t;
58 
60  void operator()()
61  {
62  os_ <<
63  "#! /bin/sh\n"
64  "\n"
65  "me=$(basename \"$0\")\n"
66  "medir=$(mktemp -d \"/tmp/$me.XXXXXX\") || exit 1\n"
67  "\n";
68 
69  os_ <<
70  "arc_type=" << arc_type_() << "\n"
71  "\n";
72 
73  // Provide the symbols first, as when reading EFSM, knowing
74  // how \e is represented will help reading the transitions.
75  print_symbols_();
76 
77  os_ <<
78  "cat >$medir/transitions.fsm <<\\EOFSM";
80  os_ <<
81  "\n"
82  "EOFSM\n"
83  "\n"
84 
85  // Some OpenFST tools seem to require an output-symbol list,
86  // even for acceptors. While fstrmepsilon perfectly works
87  // with just the isymbols, fstintersect (equivalent to our
88  // conjunction) for instance, seems to require the osymbols;
89  // this seems to be due to the fact that Open FST bases its
90  // implementation of intersect on its (transducer)
91  // composition.
92  "fstcompile" << (is_transducer ? "" : " --acceptor") << " \\\n"
93  " --arc_type=$arc_type \\\n"
94  " --keep_isymbols --isymbols=" << isymbols_ << " \\\n"
95  " --keep_osymbols --osymbols=" << osymbols_ << " \\\n"
96  " $medir/transitions.fsm \"$@\"\n"
97  "sta=$?\n"
98  "\n"
99  "rm -rf $medir\n"
100  "exit $sta" // No final \n.
101  ;
102  }
103 
104  private:
106  std::string arc_type_() const
107  {
108  static const auto map = getarg<std::string>
109  {
110  "weightset",
111  {
112  {"b", "standard"},
113  {"zmin", "standard"},
114  {"rmin", "standard"},
115  {"nmin", "standard"},
116  {"log", "log64"},
117  }
118  };
119  return map[ws_.sname()];
120  }
121 
122  template <typename LS>
123  void print_label_(const LS& ls, const typename LS::value_t& l) const
124  {
125  if (ls.is_special(l))
126  os_ << "\\e";
127  else
128  ls.print(l, os_, format::raw);
129  }
130 
132  template <typename Label>
133  void print_label_(const Label& l, std::false_type) const
134  {
135  print_label_(ls_, l);
136  }
137 
139  template <typename Label>
140  void print_label_(const Label& l, std::true_type) const
141  {
142  print_label_(ls_.template set<0>(), std::get<0>(l));
143  os_ << '\t';
144  print_label_(ls_.template set<1>(), std::get<1>(l));
145  }
146 
147  void print_transition_(const transition_t t) const override
148  {
149  // Don't output "pre", but an integer.
150  if (aut_->src_of(t) == aut_->pre())
151  os_ << aut_->pre() - 2;
152  else
153  aut_->print_state(aut_->src_of(t), os_);
154  if (aut_->dst_of(t) != aut_->post())
155  {
156  os_ << '\t';
157  aut_->print_state(aut_->dst_of(t), os_);
158  os_ << '\t';
159  print_label_(aut_->label_of(t), is_transducer);
160  }
161 
162  if (ws_.show_one() || !ws_.is_one(aut_->weight_of(t)))
163  {
164  os_ << '\t';
165  ws_.print(aut_->weight_of(t), os_);
166  }
167  }
168 
171  {
172  // FSM format supports a single initial state with one as
173  // weight. This requires, when we have several initial
174  // states or an non, to "exhibit" pre() and spontaneous transitions.
175  // Avoid this when possible.
176  auto inis = initial_transitions(aut_);
177  if (inis.size() != 1
178  || !ws_.is_one(aut_->weight_of(inis.front())))
179  for (auto t : inis)
180  {
181  os_ << '\n';
182  // Yes, this means that we display pre as -1U, which is
183  // a large unsigned integer. But that is well supported
184  // by OpenFST which renumbers the states continuously
185  // from 0.
187  }
188 
189  // We _must_ start by the initial state.
190  {
191  std::vector<state_t> states(std::begin(aut_->states()),
192  std::end(aut_->states()));
193  boost::sort(states,
194  [this](state_t l, state_t r)
195  {
196  return (std::forward_as_tuple(!aut_->is_initial(l), l)
197  < std::forward_as_tuple(!aut_->is_initial(r), r));
198  });
199  for (auto s: states)
200  this->print_state_(s);
201  }
202  for (auto t : final_transitions(aut_))
203  {
204  os_ << '\n';
206  }
207  }
208 
221  template <typename LabelSet, typename Labels, typename GetLabel>
222  auto add_alphabet_(const LabelSet& ls, Labels& labels, GetLabel get_label)
223  -> std::enable_if_t<has_generators_mem_fn<LabelSet>{}>
224  {
225  for (auto l : ls.generators())
226  labels.insert(get_label(ls.value(l)));
227  }
228 
232  template <typename LabelSet, typename Labels, typename GetLabel>
233  auto add_alphabet_(const LabelSet&, Labels&, GetLabel)
234  -> std::enable_if_t<!has_generators_mem_fn<LabelSet>{}>
235  {}
236 
261  template <typename LabelSet, typename GetLabel>
262  void print_symbols_(const std::string& name,
263  const LabelSet& ls,
264  GetLabel get_label)
265  {
266  // The labels we declare.
267  using labelset_t = LabelSet;
268  using label_t = typename labelset_t::value_t;
269 
270  auto labels = std::set<label_t, vcsn::less<labelset_t>>{};
271  // If there is an alphabet, include it, to preserve the
272  // context in round trips.
273  add_alphabet_(*aut_->labelset(), labels, get_label);
274  // In any case, insert all our labels.
275  for (auto t : transitions(aut_))
276  labels.insert(get_label(aut_->label_of(t)));
277 
278  // Sorted per label name, which is fine, and deterministic.
279  // Start with special/epsilon. Show it as \e.
280  os_ <<
281  "cat >" << name << " <<\\EOFSM\n"
282  "\\e\t0\n";
283  size_t num = 0;
284  for (const auto& l: labels)
285  if (!ls.is_one(l))
286  {
287  ls.print(l, os_, format::raw);
288  os_ << '\t' << ++num << '\n';
289  }
290  os_ <<
291  "EOFSM\n"
292  "\n";
293  }
294 
296  template <typename>
297  void
298  print_symbols_impl_(std::false_type)
299  {
300  print_symbols_(isymbols_,
301  ls_,
302  [](label_t l) { return l; });
303  }
304 
306  template <typename>
307  void
308  print_symbols_impl_(std::true_type)
309  {
310  print_symbols_(isymbols_,
311  ls_.template set<0>(),
312  [](const label_t& l) { return std::get<0>(l); });
313  print_symbols_(osymbols_,
314  ls_.template set<1>(),
315  [](const label_t& l) { return std::get<1>(l); });
316  }
317 
318  void
319  print_symbols_()
320  {
321  print_symbols_impl_<automaton_t>(is_transducer);
322  }
323 
326  using is_transducer_t =
327  std::integral_constant<bool,
328  2 <= rank<labelset_t_of<automaton_t>>::value>;
329  const is_transducer_t is_transducer = {};
330 
332  const char* isymbols_ =
333  is_transducer ? "$medir/isymbols.txt" : "$medir/symbols.txt";
335  const char* osymbols_ =
336  is_transducer ? "$medir/osymbols.txt" : "$medir/symbols.txt";
337  };
338  }
339 
340 
344  template <Automaton Aut>
345  std::ostream&
346  efsm(const Aut& aut, std::ostream& out)
347  {
348  auto efsm = detail::efsmer<Aut>{aut, out};
349  efsm();
350  return out;
351  }
352 }
const weightset_t & ws_
Short-hand to the weightset.
Definition: grail.hh:130
const labelset_t_of< automaton_t > & ls_
Short-hand to the labelset.
Definition: grail.hh:128
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:160
const char * isymbols_
File name for input tape symbols.
Definition: efsm.hh:332
void print_label_(const Label &l, std::true_type) const
Two-tape automaton.
Definition: efsm.hh:140
std::ostream & os_
Output stream.
Definition: grail.hh:126
void print_label_(const LS &ls, const typename LS::value_t &l) const
Definition: efsm.hh:123
typename super_t::label_t label_t
Definition: efsm.hh:47
const is_transducer_t is_transducer
Definition: efsm.hh:329
Definition: a-star.hh:8
static constexpr size_t value
Definition: efsm.hh:26
Format automaton to EFSM format, based on FSM format.
Definition: efsm.hh:41
Print as is. For instance, don't try to escape labels.
Definition: format.hh:22
transition_t_of< automaton_t > transition_t
Definition: grail.hh:46
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:56
A mapping from strings to Values.
Definition: getargs.hh:33
void print_state_(const state_t s)
Output transitions, sorted lexicographically on (Label, Dest).
Definition: grail.hh:72
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:222
auto initial_transitions(const Aut &aut) -> decltype(aut->all_out(aut->pre()))
Indexes of transitions to (visible) initial states.
Definition: automaton.hh:137
Number of tapes.
Definition: efsm.hh:24
auto transitions(const Aut &aut) -> decltype(all_transitions(aut, is_special_t< Aut >
All the transition indexes between visible states.
Definition: automaton.hh:218
auto add_alphabet_(const LabelSet &, Labels &, GetLabel) -> std::enable_if_t<!has_generators_mem_fn< LabelSet >
Fill ls with the letters.
Definition: efsm.hh:233
void operator()()
Actually output aut_ on os_.
Definition: efsm.hh:60
automaton_t aut_
The automaton we have to output.
Definition: grail.hh:124
const char * osymbols_
File name for output tape symbols.
Definition: efsm.hh:335
std::ostream & efsm(const Aut &aut, std::ostream &out)
Format automaton to EFSM format, based on FSM format.
Definition: efsm.hh:346
state_t_of< automaton_t > state_t
Definition: grail.hh:41
auto sort(const Aut &a) -> permutation_automaton< Aut >
Definition: sort.hh:163
auto final_transitions(const Aut &aut) -> decltype(aut->all_in(aut->post()))
Indexes of transitions from (visible) final states.
Definition: automaton.hh:148
std::string arc_type_() const
The OpenFST name that corresponds to our weightset.
Definition: efsm.hh:106
void print_label_(const Label &l, std::false_type) const
Acceptor.
Definition: efsm.hh:133
typename super_t::state_t state_t
Definition: efsm.hh:48
label_t_of< automaton_t > label_t
Definition: grail.hh:45
typename super_t::transition_t transition_t
Definition: efsm.hh:49
Factor common bits in automaton formatting.
Definition: grail.hh:28
void print_transition_(const transition_t t) const override
Definition: efsm.hh:147
void print_transitions_()
Output all the transitions, and final states.
Definition: efsm.hh:170