Vcsn  2.5.dev
Be Rational
wordset.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <memory>
4 
5 #include <boost/range/algorithm/mismatch.hpp>
6 #include <boost/algorithm/string/predicate.hpp> // starts_with
7 #include <boost/optional.hpp>
8 
9 #include <vcsn/core/kind.hh>
10 #include <vcsn/labelset/fwd.hh>
13 #include <vcsn/labelset/letterset.hh> // for letterized_traits
14 #include <vcsn/misc/attributes.hh>
15 #include <vcsn/misc/functional.hh>
16 #include <vcsn/misc/irange.hh>
17 #include <vcsn/misc/raise.hh>
18 
19 namespace vcsn
20 {
22  template <typename GenSet>
23  class wordset: public detail::genset_labelset<GenSet>
24  {
25  public:
26  using genset_t = GenSet;
28  using self_t = wordset;
29  using genset_ptr = std::shared_ptr<const genset_t>;
30 
31  using letter_t = typename genset_t::letter_t;
32  using word_t = typename genset_t::word_t;
33 
34  using value_t = word_t;
35 
37 
38  wordset(const genset_ptr& gs)
39  : super_t{gs}
40  {}
41 
42  wordset(const genset_t& gs = {})
43  : wordset{std::make_shared<const genset_t>(gs)}
44  {}
45 
46  wordset(std::initializer_list<letter_t> letters)
47  : wordset(std::make_shared<const genset_t>(letters))
48  {}
49 
50  static symbol sname()
51  {
52  static auto res = symbol{"wordset<" + super_t::sname() + '>'};
53  return res;
54  }
55 
57  static wordset make(std::istream& is)
58  {
59  // name: wordset<char_letters(abc)>.
60  // ^^^^^^^ ^^^^^^^^^^^^^^^^^
61  // kind genset
62  eat(is, "wordset<");
63  auto gs = genset_t::make(is);
64  eat(is, '>');
65  return gs;
66  }
67 
71  bool open(bool o) const
72  {
73  return this->genset()->open(o);
74  }
75 
76  static constexpr bool is_free()
77  {
78  return false;
79  }
80 
82  template <typename... Args>
83  value_t value(Args&&... args) const
84  {
85  return value_t{std::forward<Args>(args)...};
86  }
87 
89  word_t word(const value_t& v) const
90  {
91  return v;
92  }
93 
95  static word_t
97  {
98  return v;
99  }
100 
103  static word_t
105  {
106  return v;
107  }
108 
110  static int compare(const value_t& l, const value_t& r)
111  {
112  return genset_t::compare(l, r);
113  }
114 
116  static bool
117  equal(const value_t& l, const value_t& r)
118  {
119  return l == r;
120  }
121 
123  static bool less(const letter_t& l, const letter_t& r)
124  {
125  return genset_t::less(l, r);
126  }
127 
129  static bool less(const value_t& l, const value_t& r)
130  {
131  // Be sure to use genset::less().
132  auto s1 = size(l);
133  auto s2 = size(r);
134  if (s1 < s2)
135  return true;
136  else if (s2 < s1)
137  return false;
138  else
139  return genset_t::less(l, r);
140  }
141 
142  static value_t
144  {
145  return genset_t::template special<value_t>();
146  }
147 
148  static bool
150  {
151  return v == special();
152  }
153 
154  bool
155  is_valid(const value_t& v) const
156  {
157  for (auto l: v)
158  if (!this->has(l))
159  return false;
160  return true;
161  }
162 
163  static constexpr bool
165  {
166  return false;
167  }
168 
169  static constexpr bool
171  {
172  return true;
173  }
174 
175  static constexpr bool
177  {
178  return false;
179  }
180 
181  static value_t
182  one()
183  {
184  return genset_t::empty_word();
185  }
186 
187  static bool
188  is_one(const value_t& l) ATTRIBUTE_PURE
189  {
190  return genset_t::is_empty_word(l);
191  }
192 
193  static size_t size(const value_t& v)
194  {
195  // Not v.length(), because word_t can actually be a vector
196  // (e.g., with string_letters).
197  return v.size();
198  }
199 
200  static size_t hash(const value_t& v)
201  {
202  return hash_value(v);
203  }
204 
205  value_t
206  conv(self_t, const value_t& v) const
207  {
208  return v;
209  }
210 
211  template <typename GenSet_>
212  value_t
214  typename letterset<GenSet_>::value_t v) const
215  {
216  if (ls.is_special(v))
217  return special();
218  else
219  {
220  auto res = value(v);
222  *this, ": conv: invalid label: ", str_escape(v));
223  return res;
224  }
225  }
226 
227  template <typename LabelSet_>
228  value_t
230  const typename nullableset<LabelSet_>::value_t& v) const
231  {
232  if (ls.is_one(v))
233  return one();
234  else
235  return conv(*ls.labelset(), ls.get_value(v));
236  }
237 
239  value_t
240  conv(std::istream& i, bool = true) const
241  {
242  return this->genset()->get_word(i);
243  }
244 
254  template <typename Fun>
255  void convs(std::istream& i, Fun fun) const
256  {
257  this->convs_(i, [this,fun](letter_t l) { fun(value(l)); });
258  }
259 
260  std::ostream&
261  print(const value_t& l, std::ostream& o = std::cout,
262  format fmt = {}) const
263  {
264  if (is_one(l))
265  o << (fmt == format::latex ? "\\varepsilon"
266  : fmt == format::utf8 ? "ε"
267  : "\\e");
268  else if (!is_special(l))
269  this->genset()->print(l, o, fmt);
270  return o;
271  }
272 
273  std::ostream&
274  print_set(std::ostream& o, format fmt = {}) const
275  {
276  switch (fmt.kind())
277  {
278  case format::latex:
279  this->genset()->print_set(o, fmt);
280  o << "^*";
281  break;
282  case format::sname:
283  o << "wordset<";
284  this->genset()->print_set(o, fmt);
285  o << '>';
286  break;
287  case format::text:
288  case format::utf8:
289  this->genset()->print_set(o, fmt);
290  o << '*';
291  break;
292  case format::raw:
293  assert(0);
294  break;
295  }
296  return o;
297  }
298 
300  static value_t lgcd(const value_t& w1, const value_t& w2)
301  {
302  return {w1.begin(), boost::mismatch(w1, w2).first};
303  }
304 
307  value_t ldivide(const value_t& w1, const value_t& w2) const
308  {
309  auto res = maybe_ldivide(w1, w2);
310  VCSN_REQUIRE(res,
311  *this, ": ldivide: invalid arguments: ",
312  to_string(*this, w1),
313  ", ", to_string(*this, w2));
314  return *res;
315  }
316 
317  boost::optional<value_t>
318  maybe_ldivide(const value_t& w1, const value_t& w2) const
319  {
320  using boost::algorithm::starts_with;
321  if (starts_with(w2, w1))
322  return value_t{begin(w2) + size(w1), end(w2)};
323  else
324  return boost::none;
325  }
326 
328  value_t& ldivide_here(const value_t& w1, value_t& w2) const
329  {
330  w2 = ldivide(w1, w2);
331  return w2;
332  }
333 
336  value_t rdivide(const value_t& w1, const value_t& w2) const
337  {
338  auto res = maybe_rdivide(w1, w2);
339  VCSN_REQUIRE(res,
340  *this, ": rdivide: invalid arguments: ",
341  to_string(*this, w1),
342  ", ", to_string(*this, w2));
343  return *res;
344  }
345 
346  boost::optional<value_t>
347  maybe_rdivide(const value_t& w1, const value_t& w2) const
348  {
349  using boost::algorithm::ends_with;
350  if (ends_with(w1, w2))
351  return value_t{begin(w1), end(w1) - size(w2)};
352  else
353  return boost::none;
354  }
355 
357  value_t& rdivide_here(value_t& w1, const value_t& w2) const
358  {
359  w1 = rdivide(w1, w2);
360  return w1;
361  }
362 
363  const value_t& conjunction(const value_t& l, const value_t& r) const
364  {
365  if (equal(l, r))
366  return l;
367  else
368  raise(*this,
369  ": conjunction: invalid operation (lhs and rhs are not equal): ",
370  to_string(*this, l), ", ", to_string(*this, r));
371  }
372  };
373 
374  namespace detail
375  {
377  template <typename GenSet>
378  struct letterized_traits<wordset<GenSet>>
379  {
380  static constexpr bool is_letterized = false;
381 
382  using labelset_t = nullableset<letterset<GenSet>>;
383 
384  static labelset_t labelset(const wordset<GenSet>& ls)
385  {
386  return {ls.genset()};
387  }
388  };
389 
391  template <typename GenSet>
392  struct nullableset_traits<wordset<GenSet>>
393  {
394  using type = wordset<GenSet>;
395  static type value(const wordset<GenSet>& ls)
396  {
397  return ls;
398  }
399  };
400 
401  template <typename GenSet>
402  struct law_traits<wordset<GenSet>>
403  {
404  using type = wordset<GenSet>;
405  static type value(const wordset<GenSet>& ls)
406  {
407  return ls;
408  }
409  };
410 
411  /*-------.
412  | Join. |
413  `-------*/
414 
416 #define DEFINE(Lhs, Rhs) \
417  template <typename GenSet> \
418  struct join_impl<Lhs, Rhs> \
419  { \
420  using type = Rhs; \
421  static type join(const Lhs& lhs, const Rhs& rhs) \
422  { \
423  return {set_union(*lhs.genset(), *rhs.genset())}; \
424  } \
425  }
426 
428  DEFINE(letterset<GenSet>, wordset<GenSet>);
429  DEFINE(nullableset<letterset<GenSet>>, wordset<GenSet>);
430  DEFINE(wordset<GenSet>, wordset<GenSet>);
431 #undef DEFINE
432  }
433 
435  // FIXME: Factor in genset_labelset?
436  template <typename GenSet>
437  wordset<GenSet>
438  meet(const wordset<GenSet>& lhs, const wordset<GenSet>& rhs)
439  {
440  return {set_intersection(*lhs.genset(), *rhs.genset())};
441  }
442 
443 
444  /*----------------.
445  | random_label. |
446  `----------------*/
447 
449  template <typename GenSet,
450  typename RandomGenerator = std::default_random_engine>
451  typename wordset<GenSet>::value_t
452  random_label(const wordset<GenSet>& ls,
453  RandomGenerator& gen = RandomGenerator())
454  {
455  require(!ls.generators().empty(),
456  "random_label: the alphabet needs at least 1 letter");
457  auto dis = std::uniform_int_distribution<>(0, 5);
458  auto res_label = ls.one();
459  auto pick = make_random_selector(gen);
460  for (auto _: detail::irange(dis(gen)))
461  res_label = ls.mul(res_label, ls.value(pick(ls.generators())));
462  return res_label;
463  }
464 }
value_t conv(const letterset< GenSet_ > &ls, typename letterset< GenSet_ >::value_t v) const
Definition: wordset.hh:213
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
Implementation of labels are letters.
Definition: fwd.hh:10
static constexpr bool is_expressionset()
Definition: wordset.hh:164
static bool equal(const value_t &l, const value_t &r)
Whether l == r.
Definition: wordset.hh:117
value_t conv(std::istream &i, bool=true) const
Read a word from this stream.
Definition: wordset.hh:240
static bool is_one(const value_t &l) ATTRIBUTE_PURE
Definition: wordset.hh:188
std::shared_ptr< const genset_t > genset_ptr
This class has no modeling purpose, it only serves to factor code common to letterset and wordset...
wordset(const genset_ptr &gs)
Definition: wordset.hh:38
bool open(bool o) const
Whether unknown letters should be added, or rejected.
Definition: wordset.hh:71
bool is_valid(const value_t &v) const
Definition: wordset.hh:155
wordset(const genset_t &gs={})
Definition: wordset.hh:42
static word_t letters_of_padded(const value_t &v, letter_t)
Prepare to iterate over the letters of v.
Definition: wordset.hh:104
void convs(std::istream &i, Fun fun) const
Process a label class.
Definition: wordset.hh:255
Print as a parsable type string.
Definition: format.hh:26
static value_t special()
Definition: wordset.hh:143
static bool less(const letter_t &l, const letter_t &r)
Whether l < r.
Definition: wordset.hh:123
static bool less(const value_t &l, const value_t &r)
Whether l < r.
Definition: wordset.hh:129
static constexpr bool has_one()
Definition: wordset.hh:170
auto hash_value(const T &v) -> decltype(std::hash< T >
Following the naming convention of Boost.
Definition: functional.hh:45
#define VCSN_REQUIRE(Cond,...)
A macro similar to require.
Definition: raise.hh:102
static size_t size(const value_t &v)
Definition: wordset.hh:193
ATTRIBUTE_PURE auto has(Args &&... args) const -> decltype(this->genset() -> has(std::forward< Args >(args)...))
return v
Definition: multiply.hh:362
value_t conv(self_t, const value_t &v) const
Definition: wordset.hh:206
static bool is_special(const value_t &v)
Definition: wordset.hh:149
return res
Definition: multiply.hh:399
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:130
Implementation of labels are words.
Definition: fwd.hh:31
std::ostream & print_set(std::ostream &o, format fmt={}) const
Definition: wordset.hh:274
static size_t hash(const value_t &v)
Definition: wordset.hh:200
typename genset_t::letter_t letter_t
value_t conv(const nullableset< LabelSet_ > &ls, const typename nullableset< LabelSet_ >::value_t &v) const
Definition: wordset.hh:229
value_t value(Args &&... args) const
Value constructor.
Definition: wordset.hh:83
static wordset make(std::istream &is)
Build from the description in is.
Definition: wordset.hh:57
word_t word(const value_t &v) const
Convert to a word.
Definition: wordset.hh:89
static symbol sname()
Definition: wordset.hh:50
static bool is_special(value_t v) ATTRIBUTE_PURE
Definition: letterset.hh:179
const labelset_ptr labelset() const
Definition: nullableset.hh:323
static labelset_t::value_t get_value(const value_t &v)
The (inner) value when it (the outer value) is not one.
Definition: nullableset.hh:613
Print for LaTeX.
Definition: format.hh:22
Print as rich UTF-8 text, escaped.
Definition: format.hh:30
typename helper_t::value_t value_t
Definition: nullableset.hh:187
letter_t value_t
Definition: letterset.hh:33
wordset(std::initializer_list< letter_t > letters)
Definition: wordset.hh:46
static word_t letters_of(const value_t &v)
Prepare to iterate over the letters of v.
Definition: wordset.hh:96
Definition: a-star.hh:8
static value_t one()
Definition: wordset.hh:182
static int compare(const value_t &l, const value_t &r)
Three-way comparison between l and r.
Definition: wordset.hh:110
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:21
An input/output format for valuesets.
Definition: format.hh:13
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
static constexpr bool is_free()
Definition: wordset.hh:76
STL namespace.
Implementation of labels are nullables (letter or empty).
Definition: fwd.hh:14
int compare(const Lhs &lhs, const Rhs &rhs)
Comparison between lhs and rhs.
std::ostream & str_escape(std::ostream &os, const std::string &str, const char *special=nullptr)
Output a string, escaping special characters.
Definition: escape.cc:51
void convs_(std::istream &i, Fun fun) const
Read and process a class of letters.
typename genset_t::word_t word_t
Definition: wordset.hh:32
static constexpr bool is_letterized()
Definition: wordset.hh:176
static ATTRIBUTE_PURE bool is_one(value_t l)
Definition: nullableset.hh:270
word_t value_t
Definition: wordset.hh:34
std::ostream & print(const value_t &l, std::ostream &o=std::cout, format fmt={}) const
Definition: wordset.hh:261