Vcsn  2.1
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> // outputter
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 <typename Aut>
41  class efsmer: public outputter<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  output_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  auto map = std::map<std::string, std::string>
109  {
110  {"b", "standard"},
111  {"zmin", "standard"},
112  {"rmin", "standard"},
113  {"nmin", "standard"},
114  {"log", "log64"},
115  };
116  return getargs("weightset", map, ws_.sname());
117  }
118 
119  template <typename LS>
120  void output_label_(const LS& ls, const typename LS::value_t& l) const
121  {
122  if (ls.is_special(l))
123  os_ << "\\e";
124  else
125  ls.print(l, os_, format::raw);
126  }
127 
129  template <typename Label>
130  void output_label_(const Label& l, std::false_type) const
131  {
132  output_label_(ls_, l);
133  }
134 
136  template <typename Label>
137  void output_label_(const Label& l, std::true_type) const
138  {
139  output_label_(ls_.template set<0>(), std::get<0>(l));
140  os_ << '\t';
141  output_label_(ls_.template set<1>(), std::get<1>(l));
142  }
143 
144  void output_transition_(const transition_t t) const override
145  {
146  // Don't output "pre", but an integer.
147  if (aut_->src_of(t) == aut_->pre())
148  os_ << aut_->pre() - 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  output_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 = aut_->initial_transitions();
174  if (inis.size() != 1
175  || !ws_.is_one(aut_->weight_of(inis.front())))
176  for (auto t : inis)
177  {
178  os_ << '\n';
179  // Yes, this means that we display pre as -1U, which is
180  // a large unsigned integer. But that is well supported
181  // by OpenFST which renumbers the states continuously
182  // from 0.
184  }
185 
186  // We _must_ start by the initial state.
187  {
188  std::vector<state_t> states(std::begin(aut_->states()),
189  std::end(aut_->states()));
190  boost::sort(states,
191  [this](state_t l, state_t r)
192  {
193  return (std::forward_as_tuple(!aut_->is_initial(l), l)
194  < std::forward_as_tuple(!aut_->is_initial(r), r));
195  });
196  for (auto s: states)
197  this->output_state_(s);
198  }
199  for (auto t : aut_->final_transitions())
200  {
201  os_ << '\n';
203  }
204  }
205 
218  template <typename LabelSet, typename Labels, typename GetLabel>
219  auto add_alphabet_(const LabelSet& ls, Labels& labels, GetLabel get_label)
221  {
222  for (auto l : ls.genset())
223  labels.insert(get_label(ls.value(l)));
224  }
225 
229  template <typename LabelSet, typename Labels, typename GetLabel>
230  auto add_alphabet_(const LabelSet&, Labels&, GetLabel)
232  {}
233 
258  template <typename LabelSet, typename GetLabel>
259  void output_symbols_(const std::string& name,
260  const LabelSet& ls,
261  GetLabel get_label)
262  {
263  // The labels we declare.
264  using labelset_t = LabelSet;
265  using label_t = typename labelset_t::value_t;
266 
267  auto labels = std::set<label_t, vcsn::less<labelset_t>>{};
268  // If there is an alphabet, include it, to preserve the
269  // context in round trips.
270  add_alphabet_(*aut_->labelset(), labels, get_label);
271  // In any case, insert all our labels.
272  for (auto t : aut_->transitions())
273  labels.insert(get_label(aut_->label_of(t)));
274 
275  // Sorted per label name, which is fine, and deterministic.
276  // Start with special/epsilon. Show it as \e.
277  os_ <<
278  "cat >" << name << " <<\\EOFSM\n"
279  "\\e\t0\n";
280  size_t num = 0;
281  for (const auto& l: labels)
282  if (!ls.is_one(l))
283  {
284  ls.print(l, os_, format::raw);
285  os_ << '\t' << ++num << '\n';
286  }
287  os_ <<
288  "EOFSM\n"
289  "\n";
290  }
291 
293  template <typename>
294  void
295  output_symbols_impl_(std::false_type)
296  {
297  output_symbols_(isymbols_,
298  ls_,
299  [](label_t l) { return l; });
300  }
301 
303  template <typename>
304  void
305  output_symbols_impl_(std::true_type)
306  {
307  output_symbols_(isymbols_,
308  ls_.template set<0>(),
309  [](const label_t& l) { return std::get<0>(l); });
310  output_symbols_(osymbols_,
311  ls_.template set<1>(),
312  [](const label_t& l) { return std::get<1>(l); });
313  }
314 
315  void
316  output_symbols_()
317  {
318  output_symbols_impl_<automaton_t>(is_transducer);
319  }
320 
323  using is_transducer_t =
324  std::integral_constant<bool,
325  2 <= rank<labelset_t_of<automaton_t>>::value>;
326  const is_transducer_t is_transducer = {};
327 
329  const char* isymbols_ =
330  is_transducer ? "$medir/isymbols.txt" : "$medir/symbols.txt";
332  const char* osymbols_ =
333  is_transducer ? "$medir/osymbols.txt" : "$medir/symbols.txt";
334  };
335  }
336 
337 
341  template <typename Aut>
342  std::ostream&
343  efsm(const Aut& aut, std::ostream& out)
344  {
345  detail::efsmer<Aut> efsm{aut, out};
346  efsm();
347  return out;
348  }
349 }
automaton_t aut_
The automaton we have to output.
Definition: grail.hh:124
const char * isymbols_
File name for input tape symbols.
Definition: efsm.hh:329
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
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
static constexpr size_t value
Definition: efsm.hh:26
C::mapped_type getargs(const std::string &kind, const C &map, const std::string &key)
Find a correspondance in a map.
Definition: getargs.hh:21
typename super_t::label_t label_t
Definition: efsm.hh:47
typename std::enable_if< Cond, T >::type enable_if_t
Definition: type_traits.hh:16
void output_label_(const Label &l, std::true_type) const
Two-tape automaton.
Definition: efsm.hh:137
label_t_of< automaton_t > label_t
Definition: grail.hh:45
void output_label_(const LS &ls, const typename LS::value_t &l) const
Definition: efsm.hh:120
Print as is. For instance, don't try to escape labels.
Definition: format.hh:22
void operator()()
Actually output aut_ on os_.
Definition: efsm.hh:60
auto add_alphabet_(const LabelSet &ls, Labels &labels, GetLabel get_label) -> enable_if_t< has_genset_mem_fn< LabelSet >
Fill labels with the gensets of ls.
Definition: efsm.hh:219
Number of tapes.
Definition: efsm.hh:24
const is_transducer_t is_transducer
Definition: efsm.hh:326
state_t_of< automaton_t > state_t
Definition: grail.hh:41
const char * osymbols_
File name for output tape symbols.
Definition: efsm.hh:332
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
void output_transition_(const transition_t t) const override
Definition: efsm.hh:144
Format automaton to EFSM format, based on FSM format.
Definition: efsm.hh:41
std::string arc_type_() const
The OpenFST name that corresponds to our weightset.
Definition: efsm.hh:106
typename super_t::state_t state_t
Definition: efsm.hh:48
void output_label_(const Label &l, std::false_type) const
Acceptor.
Definition: efsm.hh:130
const weightset_t & ws_
Short-hand to the weightset.
Definition: grail.hh:130
auto add_alphabet_(const LabelSet &, Labels &, GetLabel) -> enable_if_t<!has_genset_mem_fn< LabelSet >
Fill ls with the letters.
Definition: efsm.hh:230
const labelset_t_of< automaton_t > & ls_
Short-hand to the labelset.
Definition: grail.hh:128
std::ostream & os_
Output stream.
Definition: grail.hh:126
std::ostream & efsm(const Aut &aut, std::ostream &out)
Format automaton to EFSM format, based on FSM format.
Definition: efsm.hh:343
void output_state_(const state_t s)
Output transitions, sorted lexicographically on (Label, Dest).
Definition: grail.hh:72
transition_t_of< automaton_t > transition_t
Definition: grail.hh:46
void output_transitions_()
Output all the transitions, and final states.
Definition: efsm.hh:167
typename super_t::transition_t transition_t
Definition: efsm.hh:49
Factor common bits in automaton formatting.
Definition: grail.hh:28
auto sort(const Aut &a) -> permutation_automaton< Aut >
Definition: sort.hh:163