Vcsn  2.0
Be Rational
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
efsm.hh
Go to the documentation of this file.
1 #ifndef VCSN_ALGOS_EFSM_HH
2 # define VCSN_ALGOS_EFSM_HH
3 
4 # include <algorithm>
5 # include <iostream>
6 # include <map>
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 
13 namespace vcsn
14 {
15 
16  /*--------------------------.
17  | efsm(automaton, stream). |
18  `--------------------------*/
19  namespace detail
20  {
22  template <typename LabelSet>
23  struct rank
24  {
25  static constexpr size_t value = 1;
26  };
27 
28  template <typename... LabelSet>
29  struct rank<tupleset<LabelSet...>>
30  {
31  static constexpr size_t value = sizeof...(LabelSet);
32  };
33 
39  template <typename Aut>
40  class efsmer: public outputter<Aut>
41  {
42  protected:
43  using automaton_t = Aut;
45 
46  using label_t = typename super_t::label_t;
47  using state_t = typename super_t::state_t;
49 
50  using super_t::os_;
51  using super_t::aut_;
52  using super_t::ls_;
53  using super_t::ws_;
54 
55  public:
56  using super_t::super_t;
57 
59  void operator()()
60  {
61  os_ <<
62  "#! /bin/sh\n"
63  "\n"
64  "me=$(basename \"$0\")\n"
65  "medir=$(mktemp -d \"/tmp/$me.XXXXXX\") || exit 1\n"
66  "\n";
67 
68  // Provide the symbols first, as when reading EFSM, knowing
69  // how \e is represented will help reading the transitions.
71 
72  os_ <<
73  "cat >$medir/transitions.fsm <<\\EOFSM";
75  os_ <<
76  "\n"
77  "EOFSM\n"
78  "\n"
79 
80  // Some OpenFST tools seem to really require an
81  // output-symbol list, even for acceptors. While
82  // fstrmepsilon perfectly works with just the isymbols,
83  // fstintersect (equivalent to our vcsn-product: the
84  // Hadamard product) for instance, seems to require the
85  // osymbols; this seems to be due to the fact that Open FST
86  // bases its implementation of intersect on its (transducer)
87  // composition.
88  "fstcompile" << (is_transducer ? "" : " --acceptor") << " \\\n"
89  " --keep_isymbols --isymbols=" << isymbols_ << " \\\n"
90  " --keep_osymbols --osymbols=" << osymbols_ << " \\\n"
91  " $medir/transitions.fsm \"$@\"\n"
92  "sta=$?\n"
93  "\n"
94  "rm -rf $medir\n"
95  "exit $sta" // No final \n.
96  ;
97  }
98 
99  private:
100  template <typename LS>
101  void output_label_(const LS& ls, const typename LS::value_t& l)
102  {
103  if (ls.is_special(l))
104  os_ << "\\e";
105  else
106  ls.print(l, os_);
107  }
108 
110  template <typename Label>
111  void output_label_(const Label& l, std::false_type)
112  {
113  output_label_(ls_, l);
114  }
115 
117  template <typename Label>
118  void output_label_(const Label& l, std::true_type)
119  {
120  output_label_(ls_.template set<0>(), std::get<0>(l));
121  os_ << '\t';
122  output_label_(ls_.template set<1>(), std::get<1>(l));
123  }
124 
126  {
127  aut_->print_state(aut_->src_of(t), os_);
128  if (aut_->dst_of(t) != aut_->post())
129  {
130  os_ << '\t';
131  aut_->print_state(aut_->dst_of(t), os_);
132  os_ << '\t';
133  output_label_(aut_->label_of(t), is_transducer);
134  }
135 
136  if (ws_.show_one() || !ws_.is_one(aut_->weight_of(t)))
137  {
138  os_ << '\t';
139  ws_.print(aut_->weight_of(t), os_);
140  }
141  }
142 
145  {
146  // FSM format supports a single initial state with one as
147  // weight. This requires, when we have several initial
148  // states or an non, to "exhibit" pre() and spontaneous transitions.
149  // Avoid this when possible.
150  auto inis = aut_->initial_transitions();
151  if (inis.size() != 1
152  || !ws_.is_one(aut_->weight_of(inis.front())))
153  for (auto t : inis)
154  {
155  os_ << '\n';
156  // Yes, this means that we display pre as -1U, which is
157  // a large unsigned integer. But that is well supported
158  // by OpenFST which renumbers the states continuously
159  // from 0.
161  }
162 
163  // We _must_ start by the initial state.
164  {
165  std::vector<state_t> states(std::begin(aut_->states()),
166  std::end(aut_->states()));
167  std::sort(begin(states), end(states),
168  [this](state_t l, state_t r)
169  {
170  return (std::forward_as_tuple(!aut_->is_initial(l), l)
171  < std::forward_as_tuple(!aut_->is_initial(r), r));
172  });
173  for (auto s: states)
174  this->output_state_(s);
175  }
176  for (auto t : aut_->final_transitions())
177  {
178  os_ << '\n';
180  }
181  }
182 
183  template <typename LabelSet, typename Labels, typename GetLabel>
184  auto add_alphabet(const LabelSet& ls, Labels& labels,
185  GetLabel get_label, int)
186  -> decltype(ls.genset(), void())
187  {
188  for (auto l : ls.genset())
189  labels.insert(get_label(ls.value(l)));
190  }
191 
192  template <typename LabelSet, typename Labels, typename GetLabel>
193  void add_alphabet(const LabelSet&, Labels&,
194  GetLabel, long)
195  {}
196 
219  template <typename LabelSet, typename GetLabel>
220  void output_symbols_(const std::string& name,
221  const LabelSet& ls,
222  GetLabel get_label)
223  {
224  // The labels we declare.
225  using labelset_t = LabelSet;
226  using label_t = typename labelset_t::value_t;
227 
228  std::set<label_t, vcsn::less<labelset_t>> labels;
229  add_alphabet(*aut_->labelset(), labels, get_label, 0);
230  for (auto t : aut_->transitions())
231  labels.insert(get_label(aut_->label_of(t)));
232 
233  // Sorted per label name, which is fine, and deterministic.
234  // Start with special/epsilon. Show it as \e.
235  os_ <<
236  "cat >" << name << " <<\\EOFSM\n"
237  "\\e\t0\n";
238  size_t num = 0;
239  for (const auto& l: labels)
240  if (!ls.is_one(l))
241  {
242  ls.print(l, os_);
243  os_ << '\t' << ++num << '\n';
244  }
245  os_ <<
246  "EOFSM\n"
247  "\n";
248  }
249 
251  template <typename>
252  void
253  output_symbols_impl_(std::false_type)
254  {
256  ls_,
257  [](label_t l) { return l; });
258  }
259 
261  template <typename>
262  void
263  output_symbols_impl_(std::true_type)
264  {
266  ls_.template set<0>(),
267  [](const label_t& l) { return std::get<0>(l); });
269  ls_.template set<1>(),
270  [](const label_t& l) { return std::get<1>(l); });
271  }
272 
273  void
275  {
276  output_symbols_impl_<automaton_t>(is_transducer);
277  }
278 
281  using is_transducer_t =
282  std::integral_constant<bool,
285 
287  const char* isymbols_ =
288  is_transducer ? "$medir/isymbols.txt" : "$medir/symbols.txt";
290  const char* osymbols_ =
291  is_transducer ? "$medir/osymbols.txt" : "$medir/symbols.txt";
292  };
293  }
294 
295 
299  template <typename Aut>
300  std::ostream&
301  efsm(const Aut& aut, std::ostream& out)
302  {
303  detail::efsmer<Aut> efsm{aut, out};
304  efsm();
305  return out;
306  }
307 
308  namespace dyn
309  {
310  namespace detail
311  {
313  template <typename Aut, typename Ostream>
314  std::ostream& efsm(const automaton& aut, std::ostream& out)
315  {
316  return efsm(aut->as<Aut>(), out);
317  }
318 
320  (const automaton& aut, std::ostream& out) -> std::ostream&);
321  }
322  }
323 }
324 
325 #endif // !VCSN_ALGOS_EFSM_HH
std::integral_constant< bool, 2<=rank< labelset_t_of< automaton_t >>::value > is_transducer_t
Whether is a transducer (two-tape automaton) as opposed to an acceptor.
Definition: efsm.hh:283
void output_symbols_(const std::string &name, const LabelSet &ls, GetLabel get_label)
Output the mapping from label name, to label number.
Definition: efsm.hh:220
typename super_t::label_t label_t
Definition: efsm.hh:46
Number of tapes.
Definition: efsm.hh:23
REGISTER_DECLARE(accessible,(const automaton &) -> automaton)
std::shared_ptr< detail::automaton_base > automaton
Definition: automaton.hh:71
typename super_t::transition_t transition_t
Definition: efsm.hh:48
void output_label_(const Label &l, std::true_type)
Two-tape automaton.
Definition: efsm.hh:118
void output_transition_(const transition_t t)
Definition: efsm.hh:125
const weightset_t & ws_
Short-hand to the weightset.
Definition: grail.hh:147
A ValueSet which is a Cartesian product of ValueSets.
Definition: fwd.hh:20
const labelset_t_of< automaton_t > & ls_
Short-hand to the labelset.
Definition: grail.hh:145
void output_state_(const state_t s)
Output transitions, sorted lexicographically on (Label, Dest).
Definition: grail.hh:82
std::ostream & efsm(const Aut &aut, std::ostream &out)
Format automaton to EFSM format, based on FSM format.
Definition: efsm.hh:301
typename super_t::state_t state_t
Definition: efsm.hh:47
std::ostream & os_
Output stream.
Definition: grail.hh:143
static constexpr size_t value
Definition: efsm.hh:25
const is_transducer_t is_transducer
Definition: efsm.hh:284
transition_t_of< automaton_t > transition_t
Definition: grail.hh:45
const char * osymbols_
File name for output tape symbols.
Definition: efsm.hh:290
void output_label_(const Label &l, std::false_type)
Acceptor.
Definition: efsm.hh:111
void output_symbols_impl_(std::false_type)
Labels of an acceptor.
Definition: efsm.hh:253
auto sort(const Aut &a) -> permutation_automaton< Aut >
Definition: sort.hh:185
Factor common bits in automaton formatting.
Definition: grail.hh:27
auto add_alphabet(const LabelSet &ls, Labels &labels, GetLabel get_label, int) -> decltype(ls.genset(), void())
Definition: efsm.hh:184
std::ostream & efsm(const automaton &aut, std::ostream &out)
Bridge.
Definition: efsm.hh:314
void output_symbols_impl_(std::true_type)
Labels of a two-tape automaton.
Definition: efsm.hh:263
void output_symbols_()
Definition: efsm.hh:274
void add_alphabet(const LabelSet &, Labels &, GetLabel, long)
Definition: efsm.hh:193
void operator()()
Actually output aut_ on os_.
Definition: efsm.hh:59
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:36
void output_label_(const LS &ls, const typename LS::value_t &l)
Definition: efsm.hh:101
label_t_of< automaton_t > label_t
Definition: grail.hh:44
Format automaton to EFSM format, based on FSM format.
Definition: efsm.hh:40
const automaton_t & aut_
The automaton we have to output.
Definition: grail.hh:141
state_t_of< automaton_t > state_t
Definition: grail.hh:40
const char * isymbols_
File name for input tape symbols.
Definition: efsm.hh:287
variadic_mul_mixin< detail::r_impl > r
Definition: fwd.hh:42
void output_transitions_()
Output all the transitions, and final states.
Definition: efsm.hh:144