Vcsn  2.8
Be Rational
labelset.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <boost/optional.hpp>
4 #include <boost/range/algorithm/find.hpp>
5 #include <boost/range/algorithm/for_each.hpp>
6 #include <boost/range/algorithm_ext/is_sorted.hpp>
7 
8 #include <vcsn/ctx/context.hh>
9 #include <vcsn/ctx/traits.hh> // labelset_t_of
10 #include <vcsn/misc/algorithm.hh> // none_of
11 #include <vcsn/misc/functional.hh> // less
12 #include <vcsn/misc/random.hh>
13 #include <vcsn/misc/static-if.hh>
14 #include <vcsn/misc/type_traits.hh> // detect
15 
16 namespace vcsn
17 {
18  namespace detail
19  {
21  template <typename LabelSet>
23  = decltype(std::declval<LabelSet>().generators());
24 
26  template <typename LabelSet>
28 
29 
30  /*-----------.
31  | has_one. |
32  `-----------*/
33 
34  template <typename LabelSet>
35  using one_t = decltype(std::declval<LabelSet>().one());
36 
37  template <typename LabelSet>
39 
40 
41  /*-------------.
42  | label_one. |
43  `-------------*/
44 
45 #if defined __GNUC__ && !defined __clang__
46  // GCC can't figure out that this one does return, because of the template
47  // instanciation, where one of them doesn't return.
48 # pragma GCC diagnostic push
49 # pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn"
50 #endif
51 
53  template <typename LabelSet>
54  auto label_one(const LabelSet& ls)
55  -> typename LabelSet::value_t
56  {
57  return static_if<LabelSet::has_one()>
58  ([](const auto& ls) { return ls.one(); },
59  [](const auto& ls) -> typename LabelSet::value_t
60  {
61  raise(ls, ": does not feature a neutral");
62  })
63  (ls);
64  }
65 
66 #if defined __GNUC__ && !defined __clang__
67 # pragma GCC diagnostic pop
68 #endif
69 
70 
71  /*-------------------.
72  | make_letterized. |
73  `-------------------*/
74 
78  template <typename LabelSet>
80  {
81  static constexpr bool is_letterized = true;
82 
83  using labelset_t = LabelSet;
84  static labelset_t labelset(const labelset_t& ls)
85  {
86  return std::make_shared<labelset_t>(labelset_t{ls.genset()});
87  }
88  };
89 
90  template <typename LabelSet>
91  using letterized_t =
93 
94  template <typename LabelSet>
95  using is_letterized_t =
97 
98  template <typename LabelSet>
100  make_letterized(const LabelSet& ls)
101  {
103  }
104 
105 
106  /*---------------------------.
107  | make_letterized_context. |
108  `---------------------------*/
109 
110  template <typename Context>
111  using letterized_context =
114 
116  template <typename LabelSet, typename WeightSet>
119  {
120  return {make_letterized(*c.labelset()), *c.weightset()};
121  }
122 
123 
124  /*--------------------.
125  | make_nullableset. |
126  `--------------------*/
127 
136  template <typename LabelSet,
137  typename Enable = void>
139  {};
140 
142  template <typename LabelSet>
144 
146  template <typename LabelSet>
148  make_nullableset(const LabelSet& ls)
149  {
151  };
152 
153  /*----------------------------.
154  | make_nullableset_context. |
155  `----------------------------*/
156 
157  template <typename Ctx>
160 
162  template <typename LabelSet, typename WeightSet>
165  {
166  return {make_nullableset(*ctx.labelset()), *ctx.weightset()};
167  }
168 
169 
170  /*---------------.
171  | make_proper. |
172  `---------------*/
173 
181  template <typename LabelSet>
183  {
184  using type = LabelSet;
185  static type value(const LabelSet& ls)
186  {
187  return ls;
188  }
189  };
190 
192  template <typename LabelSet>
194 
196  template <typename LabelSet>
198  make_proper(const LabelSet& ls)
199  {
201  }
202 
203 
204  /*-----------------------.
205  | make_proper_context. |
206  `-----------------------*/
207 
208  template <typename Context>
209  using proper_context =
212 
214  template <typename LabelSet, typename WeightSet>
215  auto
218  {
219  return {make_proper(*ctx.labelset()), *ctx.weightset()};
220  }
221 
222 
223  /*---------------------.
224  | make_free_context. |
225  `---------------------*/
226 
227  template <typename Context>
228  using free_context =
231 
233  template <typename LabelSet, typename WeightSet>
236  {
237  return {make_proper(make_letterized(*c.labelset())), *c.weightset()};
238  }
239 
240 
241  /*---------------.
242  | make_wordset. |
243  `---------------*/
244 
248  template <typename ValueSet>
249  struct law_traits
250  {};
251 
253  template <typename LabelSet>
255 
257  template <typename LabelSet>
258  inline law_t<LabelSet>
259  make_wordset(const LabelSet& ls)
260  {
261  return law_traits<LabelSet>::value(ls);
262  };
263 
264  /*--------------------.
265  | make_word_context. |
266  `--------------------*/
267 
268  template <typename Ctx>
269  using word_context_t
270  = context<law_t<labelset_t_of<Ctx>>, weightset_t_of<Ctx>>;
271 
273  template <typename LabelSet, typename WeightSet>
276  {
277  return {make_wordset(*ctx.labelset()), *ctx.weightset()};
278  }
279 
280 
281  /*---------------------.
282  | print_label_class. |
283  `---------------------*/
284 
289  template <typename LabelSet>
290  std::ostream&
291  print_label_ranges_(const LabelSet& ls,
292  const std::vector<typename LabelSet::value_t>& letters,
293  const std::vector<typename LabelSet::value_t>& alphabet,
294  std::ostream& out,
295  format fmt)
296  {
297  for (auto it = std::begin(letters), letters_end = std::end(letters);
298  it != letters_end; ++it)
299  {
300  auto end = std::mismatch(it, letters_end,
301  boost::find(alphabet, *it),
302  alphabet.end()).first;
303  ls.print(*it, out, fmt);
304  // No range for two letters or less.
305  auto width = std::distance(it, end);
306  if (2 < width)
307  {
308  it += width - 1;
309  // Using `-` in LaTeX math mode means minus (wow, 4
310  // m-words in a row), which results in a long dash, and
311  // too much space around it.
312  out << (fmt == format::latex ? "\\textrm{-}" : "-");
313  ls.print(*it, out, fmt);
314  }
315  }
316  return out;
317  }
318 
323  template <typename LabelSet>
324  std::ostream&
325  print_label_class(const LabelSet& ls,
326  const std::vector<typename LabelSet::value_t>& letters,
327  std::ostream& out,
328  format fmt)
329  {
330  using letters_t = std::vector<typename LabelSet::value_t>;
331  // In alphabetical order.
332  auto alphabet = letters_t{};
333  for (auto l : ls.generators())
334  alphabet.emplace_back(ls.value(l));
335 
336  out << '[';
337  // If the letters are strictly increasing (hence using
338  // less_equal, not just less), and are many compared to the
339  // alphabet (say, at least two thirds), then we should probably
340  // use negated classes instead.
341  if (boost::is_sorted(letters, vcsn::less_equal<LabelSet>{})
342  && 2 * boost::distance(alphabet) < 3 * boost::distance(letters))
343  {
344  // FIXME: we can certainly do better and avoid the
345  // construction of this vector.
346  auto negated = letters_t{};
347  for (auto l: alphabet)
348  if (none_of_equal(letters, l))
349  negated.emplace_back(l);
350  out << (fmt == format::latex ? "\\hat{}" : "^");
351  print_label_ranges_(ls, negated, alphabet, out, fmt);
352  }
353  else
354  print_label_ranges_(ls, letters, alphabet, out, fmt);
355  out << ']';
356 
357  return out;
358  }
359 
360  template <typename LabelSet>
361  typename LabelSet::letters_t
362  conv_label_class_(const LabelSet& ls, std::istream& i);
363 
369  //
379  template <typename LabelSet, typename Fun>
380  void
381  conv_label_class_(const LabelSet& ls, std::istream& i, Fun fun)
382  {
383  using letter_t = typename LabelSet::letter_t;
384  using letters_t = typename LabelSet::letters_t;
385  if (i.peek() == '^')
386  {
387  i.ignore();
388  auto alphabet = letters_t{};
389  for (auto l : ls.generators())
390  alphabet.insert(l);
391  boost::for_each(set_difference(alphabet, conv_label_class_(ls, i)),
392  fun);
393  }
394  else
395  {
396  // The last letter we read, for intervals.
397  auto prev = boost::optional<letter_t>{};
398  while (i.peek() != EOF && i.peek() != ']')
399  if (i.peek() == '-')
400  {
401  i.ignore();
402  // Handle a range.
403  // FIXME: ls instead of ls.sname would be better.
404  require(prev,
405  ls.sname(), ": letter classes cannot begin with '-'");
406  require(i.peek() != ']',
407  ls.sname(), ": letter classes cannot finish with '-'");
408 
409  // [prev - l2].
410  letter_t l2 = ls.get_letter(i);
411  // Skip prev, which was already processed.
412  auto gens = ls.generators();
413  // boost::find is ambiguous between Boost.Range and
414  // Boost.Algorithms.
415  auto i = boost::range::find(gens, *prev);
416  // FIXME: Cannot use std::next here, in the case of tuples.
417  if (i != std::end(gens))
418  ++i;
419  for (;
420  i != std::end(gens) && ls.less(*i, l2);
421  ++i)
422  fun(*i);
423 
424  // The last letter. Do not do this in the loop, we
425  // might overflow the capacity of char. Check
426  // validity, so that 'z-a' is empty.
427  if (ls.less(*prev, l2))
428  fun(l2);
429 
430  prev = boost::none;
431  }
432  else
433  {
434  letter_t l = ls.get_letter(i);
435  fun(l);
436  prev = l;
437  }
438  }
439  }
440 
442  template <typename LabelSet>
443  typename LabelSet::letters_t
444  conv_label_class_(const LabelSet& ls, std::istream& i)
445  {
446  using letter_t = typename LabelSet::letter_t;
447  using letters_t = typename LabelSet::letters_t;
448 
449  auto res = letters_t{};
450  conv_label_class_(ls, i, [&res](letter_t l){ res.insert(l); });
451  return res;
452  }
453  }
454 
456  template <typename LabelSet,
457  typename RandomGenerator = std::default_random_engine>
458  typename LabelSet::value_t
459  random_label(const LabelSet& ls,
460  RandomGenerator& gen = RandomGenerator())
461  {
462  require(!ls.generators().empty(),
463  "random_label: the alphabet needs at least 1 letter");
464  // Pick a member of a container following a uniform distribution.
465  auto pick = make_random_selector(gen);
466  return ls.value(pick(ls.generators()));
467  }
468 }
typename detail::weightset_t_of_impl< base_t< ValueSet > >::type weightset_t_of
Definition: traits.hh:67
bool_constant< letterized_traits< LabelSet >::is_letterized > is_letterized_t
Definition: labelset.hh:96
auto label_one(const LabelSet &ls) -> typename LabelSet::value_t
Enjoy type inference.
Definition: labelset.hh:54
nullableset_context_t< context< LabelSet, WeightSet > > make_nullableset_context(const context< LabelSet, WeightSet > &ctx)
The nullableset context of a context.
Definition: labelset.hh:164
The LAW from a LAL.
Definition: labelset.hh:249
decltype(std::declval< LabelSet >().generators()) generators_mem_fn_t
The type of the LabelSet::generators() member function.
Definition: labelset.hh:23
A traits to compute the letterized context.
Definition: labelset.hh:79
letterized_t< LabelSet > make_letterized(const LabelSet &ls)
Definition: labelset.hh:100
static constexpr bool is_letterized
Definition: labelset.hh:81
static type value(const LabelSet &ls)
Definition: labelset.hh:185
An input/output format for valuesets.
Definition: format.hh:13
decltype(std::declval< LabelSet >().one()) one_t
Definition: labelset.hh:35
word_context_t< context< LabelSet, WeightSet > > make_word_context(const context< LabelSet, WeightSet > &ctx)
The wordset context of a context.
Definition: labelset.hh:275
LabelSet::letters_t conv_label_class_(const LabelSet &ls, std::istream &i)
Read a set of letters (hence, guaranteed in order, and unique).
Definition: labelset.hh:444
free_context< context< LabelSet, WeightSet > > make_free_context(const context< LabelSet, WeightSet > &c)
The free context for c.
Definition: labelset.hh:235
std::integral_constant< bool, B > bool_constant
Definition: type_traits.hh:12
From a labelset, its non-nullable labelset.
Definition: labelset.hh:182
Functor to compare Values of ValueSets.
Definition: functional.hh:104
static labelset_t labelset(const labelset_t &ls)
Definition: labelset.hh:84
proper_t< LabelSet > make_proper(const LabelSet &ls)
The corresponding proper LabelSet.
Definition: labelset.hh:198
Definition: a-star.hh:8
typename proper_traits< LabelSet >::type proper_t
The type of the corresponding proper LabelSet.
Definition: labelset.hh:193
The smallest nullableset which includes LabelSet.
Definition: labelset.hh:138
typename letterized_traits< LabelSet >::labelset_t letterized_t
Definition: labelset.hh:92
bool none_of_equal(const Range &r, const Value &value)
Definition: algorithm.hh:202
typename law_traits< LabelSet >::type law_t
The smallest wordset that includes LabelSet.
Definition: labelset.hh:254
random_selector< RandomGenerator > make_random_selector(RandomGenerator &g)
Definition: random.hh:102
std::ostream & print_label_ranges_(const LabelSet &ls, const std::vector< typename LabelSet::value_t > &letters, const std::vector< typename LabelSet::value_t > &alphabet, std::ostream &out, format fmt)
Print a set of labels with ranges.
Definition: labelset.hh:291
Print for LaTeX.
Definition: format.hh:22
std::ostream & print_label_class(const LabelSet &ls, const std::vector< typename LabelSet::value_t > &letters, std::ostream &out, format fmt)
Print a set of labels (letterized) with classes.
Definition: labelset.hh:325
const labelset_ptr & labelset() const
Definition: context.hh:96
law_t< LabelSet > make_wordset(const LabelSet &ls)
The wordset of a labelset.
Definition: labelset.hh:259
nullableset_t< LabelSet > make_nullableset(const LabelSet &ls)
The nullableset of a labelset.
Definition: labelset.hh:148
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:87
letterized_context< context< LabelSet, WeightSet > > make_letterized_context(const context< LabelSet, WeightSet > &c)
The letterized context for c.
Definition: labelset.hh:118
auto make_proper_context(const context< LabelSet, WeightSet > &ctx) -> proper_context< context< LabelSet, WeightSet >>
From a context, its non-nullable context.
Definition: labelset.hh:216
typename nullableset_traits< LabelSet >::type nullableset_t
The smallest nullableset that includes LabelSet.
Definition: labelset.hh:143
const weightset_ptr & weightset() const
Definition: context.hh:101
return res
Definition: multiply.hh:399
expressionset< Context >::value_t random_label(const expressionset< Context > &rs, RandomGenerator &gen=RandomGenerator())
Random label from expressionset: limited to a single label.
Container set_difference(const Container &s1, const Container &s2)
The set of members of s1 that are not members of s2.
Definition: algorithm.hh:225
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:86