Vcsn  2.0
Be Rational
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
ratexpset.hxx
Go to the documentation of this file.
1 #include <algorithm>
2 #include <cassert>
3 #include <stdexcept>
4 
5 #include <vcsn/algos/fwd.hh> // is-valid
6 #include <vcsn/core/rat/copy.hh>
9 #include <vcsn/core/rat/size.hh>
10 #include <vcsn/core/rat/hash.hh>
12 #include <vcsn/dyn/algos.hh> // dyn::read_ratexp_string
13 #include <vcsn/dyn/fwd.hh>
14 #include <vcsn/dyn/ratexpset.hh> // dyn::make_ratexpset
15 #include <vcsn/labelset/oneset.hh>
16 #include <vcsn/misc/attributes.hh>
17 #include <vcsn/misc/cast.hh>
18 #include <vcsn/misc/stream.hh>
19 
20 namespace vcsn
21 {
22 
23  namespace rat
24  {
25 
26  template <typename Context>
29  : ctx_(ctx)
30  , identities_(identities)
31  {
33  }
34 
35  template <typename Context>
37  {
38  require(identities_ != identities_t::series
40  "series (currently) depend on weightset commutativity");
41  }
42 
43 #define DEFINE \
44  template <typename Context> \
45  inline \
46  auto \
47  ratexpset_impl<Context>
48 
50  -> std::string
51  {
52  return "ratexpset<" + context_t::sname() + '>';
53  }
54 
55  DEFINE::vname(bool full) const
56  -> std::string
57  {
58  std::string res;
59  if (full)
60  switch (identities_)
61  {
63  res += "ratexpset<";
64  break;
66  res += "seriesset<";
67  break;
68  default:
69  assert(false);
70  }
71  else
72  res += "ratexpset<";
73  res += context().vname(full) + '>';
74  return res;
75  }
76 
77  DEFINE::make(std::istream& is)
79  {
80  // name is, for instance, "ratexpset<lal_char(abcd), z>(trivial)".
81  eat(is, "ratexpset<");
82  auto ctx = Context::make(is);
83  eat(is, '>');
85  if (is.peek() == '(')
86  {
87  eat(is, '(');
88  is >> ids;
89  eat(is, ')');
90  }
91  return {ctx, ids};
92  }
93 
94  DEFINE::open(bool o) const
95  -> bool
96  {
97  return this->labelset()->open(o);
98  }
99 
100  DEFINE::context() const -> const context_t&
101  {
102  return ctx_;
103  }
104 
106  {
107  return identities_;
108  }
109 
110  DEFINE::is_series() const -> bool
111  {
112  return identities_ == identities_t::series;
113  }
114 
115  DEFINE::labelset() const -> const labelset_ptr&
116  {
117  return ctx_.labelset();
118  }
119 
120  DEFINE::weightset() const -> const weightset_ptr&
121  {
122  return ctx_.weightset();
123  }
124 
126  -> value_t
127  {
128  if (labelset_t::is_one(v))
129  return one();
130  return std::make_shared<atom_t>(v);
131  }
132 
133  DEFINE::zero() const
134  -> value_t
135  {
136  return std::make_shared<zero_t>();
137  }
138 
140  -> value_t
141  {
142  return std::make_shared<one_t>();
143  }
144 
145  template <typename Context>
147  inline
148  auto
150  -> void
151  {
152  static bool binary = !! getenv("VCSN_BINARY");
153  auto variadic = std::dynamic_pointer_cast<const variadic_t<Type>>(v);
154  if (variadic && ! binary)
155  res.insert(std::end(res), std::begin(*variadic), std::end(*variadic));
156  else
157  res.push_back(v);
158  }
159 
160  template <typename Context>
162  inline
163  auto
165  -> values_t
166  {
167  values_t res;
168  gather_<Type>(res, l);
169  gather_<Type>(res, r);
170  return res;
171  }
172 
173  DEFINE::add(value_t l, value_t r) const
174  -> value_t
175  {
176  // Trivial Identity
177  // E+0 = 0+E = E
178  value_t res = nullptr;
179  if (l->type() == type_t::zero)
180  res = r;
181  else if (r->type() == type_t::zero)
182  res = l;
183  // END: Trivial Identity
184  else if (is_series())
185  res = add_nonzero_series_(l, r);
186  else
187  res = std::make_shared<sum_t>(gather_<type_t::sum>(l, r));
188  return res;
189  }
190 
191  DEFINE::less_than_ignoring_weight_(value_t l, value_t r) const
192  -> bool
193  {
194  return less_than(unwrap_possible_lweight_(l), unwrap_possible_lweight_(r));
195  }
196 
197  DEFINE::remove_from_sum_series_(values_t addends,
198  typename values_t::iterator i) const
199  -> value_t
200  {
201  switch (addends.size())
202  {
203  case 0:
204  assert(false); // Sum node with zero addends.
205  case 1:
206  return zero();
207  case 2:
208  addends.erase(i);
209  return addends[0];
210  default:
211  addends.erase(i);
212  return std::make_shared<sum_t>(std::move(addends));
213  };
214  }
215 
216  DEFINE::insert_in_sum_series_(const sum_t& addends, value_t r) const
217  -> value_t
218  {
219  // We have to clone the addends (actually, their shared_ptr's)
220  // into something we can modify.
221  values_t copy = addends.subs();
222  assert(copy.size() > 0);
223 
224  // Find the right spot where to insert r.
225  const auto& ws = weightset();
226  auto rw = possibly_implicit_lweight_(r);
227  auto rn = unwrap_possible_lweight_(r);
228  auto closure =
229  [this] (value_t l, value_t r)
230  {
231  return less_than_ignoring_weight_(l, r);
232  };
233  const auto i = std::lower_bound(copy.begin(), copy.end(), rn, closure);
234  if (i != copy.end()
235  && equals(unwrap_possible_lweight_(*i), rn))
236  {
237  // An addend alraedy exists whose un-left-weighted value is rn.
238  const weight_t& iw = possibly_implicit_lweight_(*i);
239  const weight_t w = ws->add(rw, iw);
240  if (ws->is_zero(w))
241  return remove_from_sum_series_(std::move(copy), i);
242  else
243  *i = lmul(w, rn);
244  }
245  else
246  copy.insert(i, r);
247 
248  return std::make_shared<sum_t>(std::move(copy));
249  }
250 
251  DEFINE::merge_sum_series_(const sum_t& addends1, value_t aa2) const
252  -> value_t
253  {
254  value_t res = aa2;
255  for (const auto& e: addends1)
256  res = add_nonzero_series_(res, e);
257  return res;
258  }
259 
260  DEFINE::add_nonzero_series_(value_t l, value_t r) const
261  -> value_t
262  {
263  assert(! is_zero(r));
264  if (l->type() == type_t::sum)
265  {
266  const auto ls = down_pointer_cast<const sum_t>(l);
267 
268  if (r->type() == type_t::sum)
269  return merge_sum_series_(*ls, r);
270  else
271  return insert_in_sum_series_(*ls, r);
272  }
273  else if (r->type() == type_t::sum)
274  return add_nonzero_series_(r, l);
275  else
276  {
277  // Neither argument is a sum.
278  auto ls = std::make_shared<sum_t>(values_t{l}); // Not in normal form.
279  return insert_in_sum_series_(*ls, r);
280  }
281  }
282 
283  DEFINE::type_ignoring_lweight_(value_t e) const
284  -> type_t
285  {
286  return unwrap_possible_lweight_(e)->type();
287  }
288 
289  DEFINE::possibly_implicit_lweight_(value_t e) const
290  -> weight_t
291  {
292  if (auto lw = std::dynamic_pointer_cast<const lweight_t>(e))
293  return lw->weight();
294  else
295  return weightset()->one();
296  }
297 
298  DEFINE::unwrap_possible_lweight_(value_t e) const
299  -> value_t
300  {
301  if (auto lw = std::dynamic_pointer_cast<const lweight_t>(e))
302  return lw->sub();
303  else
304  return e;
305  }
306 
307  DEFINE::mul(value_t l, value_t r) const
308  -> value_t
309  {
310  if (is_series())
311  return mul_series_(l, r);
312  else
313  return mul_expressions_(l, r);
314  }
315 
316  DEFINE::mul_expressions_(value_t l, value_t r) const
317  -> value_t
318  {
319  return mul_(l, r, false);
320  }
321 
322  DEFINE::mul_series_(value_t l, value_t r) const
323  -> value_t
324  {
325  return mul_(l, r, true);
326  }
327 
328  DEFINE::mul_(value_t l, value_t r, bool series) const
329  -> value_t
330  {
331  value_t res = nullptr;
332  // Trivial Identity: T in TAF-Kit doc.
333  // E.0 = 0.E = 0.
334  if (l->type() == type_t::zero)
335  res = l;
336  else if (r->type() == type_t::zero)
337  res = r;
338  // U_K: E.(<k>1) ⇒ E<k>, subsuming T: E.1 = E.
339  else if (type_ignoring_lweight_(r) == type_t::one)
340  res = rmul(l, possibly_implicit_lweight_(r));
341  // U_K: (<k>1).E ⇒ <k>E, subsuming T: 1.E = E.
342  else if (type_ignoring_lweight_(l) == type_t::one)
343  res = lmul(possibly_implicit_lweight_(l), r);
344  // END: Trivial Identity
345  else if (series) // Different from is_series().
346  res = nontrivial_mul_series_(l, r);
347  else
348  res = nontrivial_mul_expressions_(l, r);
349  return res;
350  }
351 
352  DEFINE::is_unweighted_nonsum_(value_t v) const
353  -> bool
354  {
355  assert(v->type() != type_t::lweight);
356  // Of course we can assume v's subterms to be well-formed according
357  // to our invariants: for example zero won't occur within a product.
358  switch (v->type())
359  {
360  case type_t::sum:
361  return false;
362  default:
363  return true;
364  }
365  }
366 
367  DEFINE::is_nonsum_(value_t v) const
368  -> bool
369  {
370  return is_unweighted_nonsum_(unwrap_possible_lweight_(v));
371  }
372 
373  DEFINE::mul_atoms_(const label_t& a, const label_t& b) const
374  -> value_t
375  {
376  return mul_atoms_(a, b, typename is_law<Context>::type{});
377  }
378 
379  DEFINE::mul_atoms_(const label_t& a, const label_t& b, std::true_type) const
380  -> value_t
381  {
382  return atom(labelset()->concat(a, b));
383  }
384 
385  DEFINE::mul_atoms_(const label_t& a, const label_t& b, std::false_type) const
386  -> value_t
387  {
388  return std::make_shared<prod_t>(values_t{atom(a), atom(b)});
389  }
390 
391  DEFINE::mul_unweighted_nontrivial_products_(value_t a, value_t b) const
392  -> value_t
393  {
394  assert(! is_zero(a));
395  assert(! is_zero(b));
396  assert(! is_one(a));
397  assert(! is_one(b));
398  assert(! std::dynamic_pointer_cast<const lweight_t>(a));
399  assert(! std::dynamic_pointer_cast<const lweight_t>(b));
400 
401  // The result is a product holding a's factors followed by b's
402  // factors, with one exception: if the last factors of a can be
403  // combined with the first factor of b then the two have to be
404  // merged in the result.
405  return concat(a, b);
406  }
407 
408  DEFINE::mul_products_(value_t a, value_t b) const
409  -> value_t
410  {
411  assert(! is_zero(a));
412  assert(! is_zero(b));
413  value_t na = unwrap_possible_lweight_(a), nb = unwrap_possible_lweight_(b);
414 
415  if (na->type() == type_t::one)
416  return lmul(possibly_implicit_lweight_(a), b);
417  else if (nb->type() == type_t::one)
418  return lmul(weightset()->mul(possibly_implicit_lweight_(a),
419  possibly_implicit_lweight_(b)),
420  na);
421  else
422  return lmul(weightset()->mul(possibly_implicit_lweight_(a),
423  possibly_implicit_lweight_(b)),
424  mul_unweighted_nontrivial_products_(na, nb));
425  }
426 
427  DEFINE::nontrivial_mul_expressions_(value_t l, value_t r) const
428  -> value_t
429  {
430  return std::make_shared<prod_t>(gather_<type_t::prod>(l, r));
431  }
432 
433  DEFINE::nontrivial_mul_series_(value_t l, value_t r) const
434  -> value_t
435  {
436  // Compute the result by distributing product over sum. We have
437  // to use add rather than just build a vector in order, since the
438  // addend order in the result will not follow the order in l.
439  const auto& lt = type_ignoring_lweight_(l), rt = type_ignoring_lweight_(r);
440  value_t res = zero();
441  if (lt == type_t::sum)
442  // l is a sum, and r might be as well.
443  for (const auto& la: *down_pointer_cast<const sum_t>(l))
444  res = add(res, mul(la, r));
445  else if (rt == type_t::sum)
446  // r is a sum, l is not.
447  for (const auto& ra: *down_pointer_cast<const sum_t>(r))
448  res = add(res, mul(l, ra));
449  // Neither l nor r is a sum.
450  else if (is_nonsum_(l) && is_nonsum_(r))
451  return mul_products_(l, r);
452  else
453  {
454  weight_t lw = possibly_implicit_lweight_(l)
455  , rw = possibly_implicit_lweight_(r);
456  value_t nl = unwrap_possible_lweight_(l)
457  , nr = unwrap_possible_lweight_(r);
458  return lmul(weightset()->mul(lw, rw),
459  std::make_shared<prod_t>(gather_<type_t::prod>(nl, nr)));
460  }
461  return res;
462  }
463 
465  -> value_t
466  {
467  value_t res = nullptr;
468  // Trivial Identity: 0&E = 0.
469  if (l->type() == type_t::zero)
470  res = l;
471  // Trivial Identity: E&0 = 0.
472  else if (r->type() == type_t::zero)
473  res = r;
474  // <k>1&<h>1 = <kh>1.
475  else if (type_ignoring_lweight_(l) == type_t::one
476  && type_ignoring_lweight_(r) == type_t::one)
477  res = lmul(weightset()->mul(possibly_implicit_lweight_(l),
478  possibly_implicit_lweight_(r)),
479  one());
480  // <k>a&<h>a = <kh>a. <k>a&<h>b = 0.
481  else if (type_ignoring_lweight_(l) == type_t::atom
482  && type_ignoring_lweight_(r) == type_t::atom)
483  {
484  auto lhs =
485  down_pointer_cast<const atom_t>(unwrap_possible_lweight_(l))->value();
486  auto rhs =
487  down_pointer_cast<const atom_t>(unwrap_possible_lweight_(r))->value();
488  if (labelset()->equals(lhs, rhs))
489  res = rmul(l, possibly_implicit_lweight_(r));
490  else
491  res = zero();
492  }
493  // <k>1&<h>a = 0, <k>a&<h>1 = 0.
494  else if ( (type_ignoring_lweight_(l) == type_t::one
495  && type_ignoring_lweight_(r) == type_t::atom)
496  || (type_ignoring_lweight_(l) == type_t::atom
497  && type_ignoring_lweight_(r) == type_t::one))
498  res = zero();
499  // END: Trivial Identity
500  else
501  res = std::make_shared<conjunction_t>(gather_<type_t::conjunction>(l, r));
502  return res;
503  }
504 
506  -> value_t
507  {
508  value_t res = nullptr;
509  // 0\E = 0{c}.
510  if (l->type() == type_t::zero)
511  res = complement(zero());
512  // 1\E = E.
513  else if (l->type() == type_t::one)
514  res = r;
515  // E\0 = 0.
516  else if (r->type() == type_t::zero)
517  res = r;
518  else
519  res = std::make_shared<ldiv_t>(values_t{l, r});
520  return res;
521  }
522 
523  DEFINE::rdiv(value_t l, value_t r) const
524  -> value_t
525  {
526  // l/r = (r{T} {\} l{T}){T}.
528  }
529 
531  -> value_t
532  {
533  value_t res = nullptr;
534  // Trivial Identity.
535  // E:0 = 0:E = 0.
536  if (l->type() == type_t::zero)
537  res = l;
538  else if (r->type() == type_t::zero)
539  res = r;
540  // E:1 = 1:E = E.
541  else if (l->type() == type_t::one)
542  res = r;
543  else if (r->type() == type_t::one)
544  res = l;
545  // END: Trivial Identity
546  else
547  res = std::make_shared<shuffle_t>(gather_<type_t::shuffle>(l, r));
548  return res;
549  }
550 
551  DEFINE::concat(value_t l, value_t r) const
552  -> value_t
553  {
554  return concat_(l, r, typename is_law<Context>::type{});
555  }
556 
557  // Concatenation when not LAW.
558  DEFINE::concat_(value_t l, value_t r, std::false_type) const
559  -> value_t
560  {
561  return mul_expressions_(l, r);
562  }
563 
564  // Concatenation when LAW.
565  DEFINE::concat_(value_t l, value_t r, std::true_type) const
566  -> value_t
567  {
568  // concat((ab).c, d.(ef)) = (ab).(cd).(ef).
569  //
570  // Store (ab) in ratexp, then concat(c, d) if c and d are atoms,
571  // otherwise c then d, then (ef).
572  if ((l->type() == type_t::atom || l->type() == type_t::prod)
573  && (r->type() == type_t::atom || r->type() == type_t::prod))
574  {
575  // Left-hand sides.
576  values_t ls;
577  gather_<type_t::prod>(ls, l);
578  // Right-hand sides.
579  values_t rs;
580  gather_<type_t::prod>(rs, r);
581 
582  if (ls.back()->type() == type_t::atom
583  && rs.front()->type() == type_t::atom)
584  {
585  auto lhs = std::dynamic_pointer_cast<const atom_t>(ls.back());
586  auto rhs = std::dynamic_pointer_cast<const atom_t>(rs.front());
587  ls.back() = atom(labelset()->concat(lhs->value(), rhs->value()));
588  ls.insert(ls.end(), rs.begin() + 1, rs.end());
589  }
590  else
591  ls.insert(ls.end(), rs.begin(), rs.end());
592  if (ls.size() == 1)
593  return ls.front();
594  else
595  return std::make_shared<prod_t>(ls);
596  }
597  else
598  // Handle all the trivial identities.
599  return mul_expressions_(l, r);
600  }
601 
603  -> value_t
604  {
605  if (e->type() == type_t::zero)
606  // Trivial one
607  // (0)* == 1
608  return one();
609  else
610  {
611  value_t res = std::make_shared<star_t>(e);
612  require(!is_series() || is_valid(*this, res),
613  "star argument ", e, " not starrable");
614  return res;
615  }
616  }
617 
619  -> value_t
620  {
621  // Trivial identity: (k.E){c} => E{c}, (E.k){c} => E{c}.
622  // Without it, derived-term (<2>a)*{c} fails to terminate.
623  if (auto w = std::dynamic_pointer_cast<const lweight_t>(e))
624  return complement(w->sub());
625  else if (auto w = std::dynamic_pointer_cast<const rweight_t>(e))
626  return complement(w->sub());
627  else
628  return std::make_shared<complement_t>(e);
629  }
630 
632  -> value_t
633  {
634  value_t res = nullptr;
635  // Trivial Identity.
636  // 0{T} = 0.
637  if (e->type() == type_t::zero)
638  res = e;
639  // 1{T} = 1.
640  else if (e->type() == type_t::one)
641  res = e;
642  // a{T} = a, (abc){T} = cba.
643  else if (auto l = std::dynamic_pointer_cast<const atom_t>(e))
644  res = atom(labelset()->transpose(l->value()));
645  // END: Trivial Identity
646  else
647  res = std::make_shared<transposition_t>(e);
648  return res;
649  }
650 
651  /*----------.
652  | weights. |
653  `----------*/
654 
655  DEFINE::lmul(const weight_t& w, value_t e) const
656  -> value_t
657  {
658  // Trivial identities <k>0 => 0, <1>E => E.
659  if (e->type() == type_t::zero || weightset()->is_one(w))
660  return e;
661  // Trivial identity: <0>E => 0.
662  else if (weightset()->is_zero(w))
663  return zero();
664  // Trivial identity: <k>(<h>E) => <kh>E.
665  else if (auto lw = std::dynamic_pointer_cast<const lweight_t>(e))
666  return lmul(weightset()->mul(w, lw->weight()), lw->sub());
667  // General case: <k>E.
668  else if (is_series() && e->type() == type_t::sum)
669  {
670  const auto& s = down_pointer_cast<const sum_t>(e);
671  // We can build the result faster by emplace_back'ing addends without
672  // passing thru add; the order will be the same as in *ss.
673  values_t addends;
674  for (auto& a: *s)
675  addends.emplace_back(lmul(w, a));
676  return std::make_shared<sum_t>(std::move(addends));
677  }
678  else
679  return std::make_shared<lweight_t>(w, e);
680  }
681 
682  DEFINE::rmul(value_t e, const weight_t& w) const
683  -> value_t
684  {
685  // Trivial identity: E<0> => 0.
686  if (weightset()->is_zero(w))
687  return zero();
688  // Trivial identity: E<1> => E.
689  else if (weightset()->is_one(w))
690  return e;
691  else if (e->is_leaf())
692  // Can only have left weights and lmul takes care of normalization.
693  return lmul(w, e);
694  // Trivial identity: (<k>E)<h> => <k>(E<h>).
695  else if (auto lw = std::dynamic_pointer_cast<const lweight_t>(e))
696  return lmul(lw->weight(), rmul(lw->sub(), w));
697  // Trivial identity: (E<k>)<h> => E<kh>.
698  else if (auto rw = std::dynamic_pointer_cast<const rweight_t>(e))
699  return rmul(rw->sub(), weightset()->mul(rw->weight(), w));
700  // Series: distribute rmul on sums.
701  else if (is_series() && e->type() == type_t::sum)
702  {
703  const auto& s = down_pointer_cast<const sum_t>(e);
704  // Differently from the lmul case here the order of addends in
705  // the result may be different from the order in *ss, so we
706  // have to use add.
707  value_t res = zero();
708  for (auto& a: *s)
709  res = add(res, rmul(a, w));
710  return res;
711  }
712  // General case: E<k>.
713  else
714  return std::make_shared<rweight_t>(w, e);
715  }
716 
717  /*----------------------------------.
718  | ratexpset as a WeightSet itself. |
719  `----------------------------------*/
720 
721  DEFINE::is_zero(value_t v) const
722  -> bool
723  {
724  return v->type() == type_t::zero;
725  }
726 
727  DEFINE::is_one(value_t v)
728  -> bool
729  {
730  return (v->type() == type_t::one);
731  }
732 
734  -> bool
735  {
736  size<ratexpset_impl> sizer;
737  size_t l = sizer(lhs), r = sizer(rhs);
738 
739  if (l < r)
740  return true;
741  else if (l > r)
742  return false;
743  else
744  {
745  using less_than_t = rat::less_than<ratexpset_impl>;
746  less_than_t lt;
747  return lt(lhs, rhs);
748  }
749  }
750 
751  DEFINE::equals(value_t lhs, value_t rhs)
752  -> bool
753  {
754  return ! less_than(lhs, rhs) && ! less_than(rhs, lhs);
755  }
756 
757  DEFINE::hash(const value_t& v)
758  -> size_t
759  {
761  return hasher(v);
762  }
763 
765  -> value_t
766  {
767  if (identities() == rs.identities())
768  return v;
769  else
770  return copy(rs, *this, v);
771  }
772 
773  template <typename Context>
774  template <typename GenSet>
775  inline
776  auto
778  typename letterset<GenSet>::value_t v) const
779  -> value_t
780  {
781  return atom(labelset()->conv(ls, v));
782  }
783 
784  DEFINE::conv(b, typename b::value_t v) const
785  -> value_t
786  {
787  return v ? one() : zero();
788  }
789 
790  DEFINE::conv(const z& ws, typename z::value_t v) const
791  -> value_t
792  {
793  return lmul(weightset()->conv(ws, v), one());
794  }
795 
796  DEFINE::conv(const q& ws, typename q::value_t v) const
797  -> value_t
798  {
799  return lmul(weightset()->conv(ws, v), one());
800  }
801 
802  DEFINE::conv(const r& ws, typename r::value_t v) const
803  -> value_t
804  {
805  return lmul(weightset()->conv(ws, v), one());
806  }
807 
808  DEFINE::conv(const zmin& ws, typename zmin::value_t v) const
809  -> value_t
810  {
811  return lmul(weightset()->conv(ws, v), one());
812  }
813 
814  template <typename Context>
815  template <typename Ctx2>
816  inline
817  auto
819  typename ratexpset_impl<Ctx2>::value_t r) const
820  -> value_t
821  {
822  return copy(rs, *this, r);
823  }
824 
825  DEFINE::conv(std::istream& is) const
826  -> value_t
827  {
828  auto dynres = dyn::read_ratexp(is, dyn::make_ratexpset(*this));
829  const auto& res = dynres->template as<ratexpset_impl>();
830  return res.ratexp();
831  }
832 
833  DEFINE::print(const value_t v, std::ostream& o,
834  symbol format) const
835  -> std::ostream&
836  {
837  using printer_t = printer<ratexpset_impl>;
838  printer_t print(*this, o);
839  print.format(format);
840  return print(v);
841  }
842 
843  DEFINE::transpose(const value_t v) const
844  -> value_t
845  {
847  return tr(v);
848  }
849 
850  template <typename Context>
851  template <typename... Args>
852  inline
853  auto
855  -> value_t
856  {
857  return letter_class_<labelset_t>(std::forward<Args>(args)...,
858  std::is_same<labelset_t, vcsn::oneset>{});
859  }
860 
861  template <typename Context>
862  template <typename LabelSet_>
863  inline
864  auto
866  (std::set<std::pair<typename LabelSet_::letter_t,
867  typename LabelSet_::letter_t>> ccs,
868  bool accept,
869  std::false_type) const
870  -> value_t
871  {
872  value_t res = zero();
873  auto gens = labelset()->genset();
874  // FIXME: This piece of code screams for factoring. Yet, I want
875  // to avoid useless costs such as building a empty/full set of
876  // letters for [^].
877 
878  // [a-c].
879  if (accept)
880  for (const auto& cc: ccs)
881  {
882  auto i = std::find(std::begin(gens), std::end(gens), cc.first);
883  auto end = std::find(i, std::end(gens), cc.second);
884  require(end != std::end(gens),
885  "invalid letter interval: ",
886  to_string(*labelset(), labelset()->value(std::get<0>(cc))),
887  '-',
888  to_string(*labelset(), labelset()->value(std::get<1>(cc))));
889  for (end = std::next(end); i != end; ++i)
890  res = add(res, atom(labelset()->value(*i)));
891  }
892  // [^].
893  else if (ccs.empty())
894  for (auto l: gens)
895  res = add(res, atom(labelset()->value(l)));
896  // [^a-z].
897  else
898  {
899  // Match the letters that are in no interval.
900  std::set<typename LabelSet_::letter_t> accepted;
901  for (const auto& cc: ccs)
902  {
903  auto i = std::find(std::begin(gens), std::end(gens), cc.first);
904  auto end = std::find(i, std::end(gens), cc.second);
905  require(end != std::end(gens),
906  "invalid letter interval: ",
907  to_string(*labelset(), labelset()->value(std::get<0>(cc))),
908  '-',
909  to_string(*labelset(), labelset()->value(std::get<1>(cc))));
910  for (end = std::next(end); i != end; ++i)
911  accepted.emplace(*i);
912  }
913  for (auto c: gens)
914  if (!has(accepted, c))
915  res = add(res, atom(labelset()->value(c)));
916  }
917  require(!is_zero(res),
918  "invalid empty letter class");
919  return res;
920  }
921 
922  template <typename Context>
923  template <typename LabelSet_, typename... Args>
924  inline
925  auto
927  std::true_type) const
928  -> value_t
929  {
930  return one();
931  }
932 
933 #undef DEFINE
934 
935 } // namespace rat
936 } // namespace vcsn
variadic< type_t::ldiv, Context > ldiv
Definition: fwd.hh:132
unary< type_t::complement, Context > complement
Definition: fwd.hh:110
typename node_t::values_t values_t
A list (vector) of ratexps.
Definition: ratexpset.hh:73
An inner node with multiple children.
Definition: fwd.hh:123
typename node_t::type_t type_t
Type tag for AST classes.
Definition: ratexpset.hh:71
OutRatExpSet::value_t copy(const InRatExpSet &in_rs, const OutRatExpSet &out_rs, const typename InRatExpSet::value_t &v)
Definition: copy.hh:131
ratexpset make_ratexpset(const context &ctx,::vcsn::rat::identities is)
Build an ratexpset from its context.
Definition: make-context.cc:57
unary< type_t::transposition, Context > transposition
Definition: fwd.hh:116
typename node_t::value_t value_t
A ratexp (a shared pointer to a tree).
Definition: ratexpset.hh:69
std::string to_string(identities i)
Definition: identities.cc:13
void require_weightset_commutativity() const
Definition: ratexpset.hxx:36
Trivial identities only.
void gather_(values_t &res, value_t v) const
Push v in res, applying associativity if possible.
pair_automaton< Aut > pair(const Aut &aut, bool keep_initials=false)
Definition: pair.hh:214
boost::flyweight< std::string, boost::flyweights::no_tracking > symbol
An internalized string.
Definition: symbol.hh:24
std::string sname()
Definition: name.hh:31
typename context_t::labelset_ptr labelset_ptr
Definition: ratexpset.hh:37
variadic_mul_mixin< detail::b_impl > b
Definition: fwd.hh:38
auto conv(const ValueSet &vs, const std::string &str, Args &&...args) -> decltype(vs.conv(std::declval< std::istream & >(), std::forward< Args >(args)...))
Parse str via vs.conv.
Definition: stream.hh:29
bool is_valid(const Aut &aut)
Definition: is-valid.hh:138
typename weightset_t::value_t weight_t
Definition: ratexpset.hh:40
typename context_t::weightset_ptr weightset_ptr
Definition: ratexpset.hh:38
label_t_of< context_t > label_t
Definition: ratexpset.hh:39
std::ostream & print(const ValueSet &vs, const typename ValueSet::value_t &v, std::ostream &o, const std::string &format)
Applies to (ValueSet, Value, ostream, string): for expansionset, polynomialset, ratexpset, and weightset.
Definition: print.hh:51
type_t
The possible types of ratexps.
Definition: fwd.hh:31
value_t letter_class(Args &&...chars) const
A ratexp matching one character amongst chars.
#define down_pointer_cast
Definition: cast.hh:16
Trivial identities plus series identities.
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:38
ratexpset_impl(const context_t &ctx, identities_t identities)
Constructor.
Definition: ratexpset.hxx:27
A typed ratexp set.
Definition: fwd.hh:161
letter_t value_t
Definition: letterset.hh:33
std::istringstream is
The input stream: the specification to translate.
Definition: translate.cc:329
std::string vname(T &t)
Definition: name.hh:65
constant< type_t::one, Context > one
Definition: fwd.hh:100
constant< type_t::zero, Context > zero
Definition: fwd.hh:97
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:36
std::shared_ptr< const detail::context_base > context
Definition: context.hh:71
Aut transpose(const transpose_automaton< Aut > &aut)
Definition: transpose.hh:230
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:37
ratexp read_ratexp(std::istream &is, const ratexpset &rs, const std::string &format="default")
Read a ratexp from a stream.
Definition: read.cc:62
Implementation of labels are letters.
Definition: fwd.hh:9
value_t letter_class_(const Args &&...chars, std::true_type) const
If labelset is oneset.
RatExpSet::value_t less_than(const RatExpSet &rs, const typename RatExpSet::value_t &v)
Definition: less-than.hh:150
identities
A ratexpset can implement several different sets of identities on expressions.
Definition: identities.hh:17
value_t conv(const letterset< GenSet > &ls, typename letterset< GenSet >::value_t v) const
variadic_mul_mixin< detail::r_impl > r
Definition: fwd.hh:42
bool has(const std::map< Key, Value, Compare, Alloc > &s, const Key &e)
Definition: map.hh:35
void require(bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:39
ATTRIBUTE_PURE auto find(const std::vector< T, Alloc > &s, const T &e) -> typename std::vector< T, Alloc >::const_iterator
Convenience wrapper around std::find.
Definition: vector.hh:66