Vcsn  2.8
Be Rational
expansionset.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <vcsn/algos/project.hh>
4 #include <vcsn/algos/split.hh> // expression_polynomialset_t
5 #include <vcsn/ctx/traits.hh>
6 #include <vcsn/misc/algorithm.hh>
7 #include <vcsn/misc/map.hh>
8 #include <vcsn/misc/static-if.hh>
9 
10 namespace vcsn
11 {
12 
13  namespace rat
14  {
15 
16  /*---------------.
17  | expansionset. |
18  `---------------*/
19 
20  template <typename ExpSet>
21  struct expansionset
22  {
23  public:
24  using expressionset_t = ExpSet;
29  using expression_t = typename expressionset_t::value_t;
31  using weight_t = typename weightset_t::value_t;
32 
35  using monomial_t = typename polynomialset_t::monomial_t;
36 
37  constexpr static const char* me() { return "expansion"; }
38 
39  // Keep it sorted to ensure determinism, and better looking
40  // results. Anyway, rough benches show no difference between
41  // map and unordered_map here.
42  using polys_t = std::map<label_t, polynomial_t, vcsn::less<labelset_t>>;
43 
45  struct value_t
46  {
48  // Default value to silence the warnings from
49  // -Wmissing-field-initializers with `value_t{weight}`.
51  };
52 
54  : rs_(rs)
55  {}
56 
58  static symbol sname()
59  {
60  static auto res
61  = symbol{"expansionset<" + expressionset_t::sname() + '>'};
62  return res;
63  }
64 
67  {
68  return rs_;
69  }
70 
73  {
74  return ps_;
75  }
76 
78  const context_t& context() const
79  {
80  return rs_.context();
81  }
82 
84  std::ostream& print_set(std::ostream& o, format fmt = {}) const
85  {
86  switch (fmt.kind())
87  {
88  case format::latex:
89  o << "\\mathsf{Expansion}[";
90  rs_.print_set(o, fmt);
91  o << ']';
92  break;
93  case format::sname:
94  o << "expansionset<";
95  rs_.print_set(o, fmt);
96  o << ">";
97  break;
98  case format::text:
99  case format::utf8:
100  o << "Expansion[";
101  rs_.print_set(o, fmt);
102  o << ']';
103  break;
104  case format::raw:
105  assert(0);
106  break;
107  }
108  return o;
109  }
110 
112  std::ostream& print(const value_t& v,
113  std::ostream& o = std::cout,
114  format fmt = {}) const
115  {
116  bool first = true;
117  if (!ws_.is_zero(v.constant) || v.polynomials.empty())
118  {
119  o << (fmt == format::latex ? "\\left\\langle "
120  : fmt == format::utf8 ? "⟨"
121  : "<");
122  ws_.print(v.constant, o, fmt.for_weights());
123  o << (fmt == format::latex ? "\\right\\rangle "
124  : fmt == format::utf8 ? "⟩"
125  : ">");
126  first = false;
127  }
128  for (const auto& p: v.polynomials)
129  {
130  if (!first)
131  o << (fmt == format::latex ? " \\oplus "
132  : fmt == format::utf8 ? " ⊕ "
133  : " + ");
134  first = false;
135  ls_.print(p.first, o, fmt.for_labels());
136  o << (fmt == format::latex ? " \\odot \\left["
137  : fmt == format::utf8 ? "⊙["
138  : ".[");
139  ps_.print(p.second, o, fmt);
140  o << (fmt == format::latex ? "\\right]"
141  : fmt == format::utf8 ? "]"
142  : "]");
143  }
144  return o;
145  }
146 
148  bool is_normal(const value_t& x) const
149  {
150  return detail::static_if<context_t::has_one()>
151  ([](const auto& ls, const value_t& x)
152  {
153  return !has(x.polynomials, ls.one());
154  },
155  [](const auto&, const value_t&)
156  {
157  return true;
158  })
159  (ls_, x);
160  }
161 
165  {
166  detail::erase_if(res.polynomials,
167  [this](auto& p)
168  {
169  return ps_.is_zero(p.second);
170  });
172  return normalize_(res, has_one);
173  }
174 
180  value_t& normalize_(value_t& res, std::true_type) const
181  {
182  auto one = ls_.one();
183  auto i = res.polynomials.find(one);
184  if (i != std::end(res.polynomials))
185  {
186  auto j = i->second.find(rs_.one());
187  if (j != std::end(i->second))
188  {
189  res.constant = ws_.add(res.constant, weight_of(*j));
190  i->second.erase(j);
191  if (ps_.is_zero(i->second))
192  res.polynomials.erase(i);
193  }
194  }
195  return res;
196  }
197 
199  value_t& normalize_(value_t& res, std::false_type) const
200  {
201  return res;
202  }
203 
212  {
214  return denormalize_(res, has_one);
215  }
216 
219  value_t& denormalize_(value_t& res, std::true_type) const
220  {
221  if (!ws_.is_zero(res.constant))
222  {
223  auto one = ls_.one();
224  ps_.add_here(res.polynomials[one],
225  polynomial_t{{rs_.one(), res.constant}});
226  res.constant = ws_.zero();
227  }
228  return res;
229  }
230 
232  value_t& denormalize_(value_t& res, std::false_type) const
233  {
234  return res;
235  }
236 
237  /*--------.
238  | Conv. |
239  `--------*/
240 
242  static value_t
243  conv(self_t, const value_t& v)
244  {
245  return v;
246  }
247 
249  template <typename OtherExpSet>
250  value_t
252  const typename expansionset<OtherExpSet>::value_t& v) const
253  {
254  const auto& other_ws = other.expressionset().weightset();
255  const auto& other_ps = other.polynomialset();
256  return {ws_.conv(other_ws, v.constant),
257  ps_.conv(other_ps, v.polynomials)};
258  }
259 
261  value_t zero() const
262  {
263  return {ws_.zero()};
264  }
265 
267  value_t one() const
268  {
269  return {ws_.one()};
270  }
271 
273  value_t atom(const label_t& l) const
274  {
275  return {ws_.zero(), {{l, ps_.one()}}};
276  }
277 
279  void add_here(value_t& lhs, const value_t& rhs) const
280  {
281  lhs.constant = ws_.add(lhs.constant, rhs.constant);
282  for (const auto& p: rhs.polynomials)
283  ps_.add_here(lhs.polynomials[p.first], p.second);
284  normalize(lhs);
285  }
286 
288  value_t add(value_t res, const value_t& rhs) const
289  {
290  add_here(res, rhs);
291  return res;
292  }
293 
295  value_t lweight(const weight_t& w, value_t res) const
296  {
297  lweight_here(w, res);
298  return res;
299  }
300 
303  {
304  if (ws_.is_zero(w))
305  res = zero();
306  else
307  {
308  res.constant = ws_.mul(w, res.constant);
309  for (auto& p: res.polynomials)
310  p.second = ps_.lweight(w, p.second);
311  }
312  return res;
313  }
314 
316  value_t rweight(const value_t& lhs, const weight_t& w) const
317  {
318  auto res = value_t{ws_.mul(lhs.constant, w)};
319  if (!ws_.is_zero(w))
320  for (auto& p: lhs.polynomials)
321  for (const auto& m: p.second)
322  ps_.add_here(res.polynomials[p.first],
323  rs_.rweight(label_of(m), w), weight_of(m));
324  return res;
325  }
326 
329  {
330  assert(ws_.is_zero(res.constant));
331  for (auto& p: res.polynomials)
332  p.second = ps_.rmul_label(p.second, rhs);
333  return res;
334  }
335 
338  {
339  res.constant = ws_.ldivide(w, res.constant);
340  for (auto& p: res.polynomials)
341  for (auto&& m: p.second)
342  weight_set(m, ws_.ldivide(w, weight_of(m)));
343  return normalize(res);
344  }
345 
346  private:
347  template <typename Conjunction>
348  void
350  const value_t&, const value_t&,
351  std::false_type,
352  Conjunction) const
353  {}
354 
355  template <typename Conjunction>
356  void
358  const value_t& l, const value_t& r,
359  std::true_type,
360  Conjunction conjunction) const
361  {
362  const auto one = ls_.one();
363 
364  // Left constant.
365  //
366  // `<k> & \e . [P]` => `\e . [<k>1 & P]`
367  // because
368  // `$ . [<k>1] & \e . [P]` => `\e . [<k>1 & P]`
369  if (!ws_.is_zero(l.constant))
370  for (const auto& rhs: r.polynomials)
371  if (ls_.is_one(rhs.first))
372  ps_.add_here(res.polynomials[rhs.first],
373  ps_.conjunction(ps_.lweight(l.constant, ps_.one()),
374  rhs.second));
375 
376  // Label one from the lhs.
377  {
378  auto i = l.polynomials.find(one);
379  if (i != std::end(l.polynomials))
380  for (const auto& rhs: r.polynomials)
381  if (!ls_.is_one(rhs.first))
382  ps_.add_here(res.polynomials[one],
383  conjunction(i->second,
384  ps_.lmul_label(rs_.atom(rhs.first),
385  rhs.second)));
386  }
387 
388  // Right constant.
389  //
390  // `\e . [P] & <k>` => `\e . [P & <k>1]`
391  if (!ws_.is_zero(r.constant))
392  for (const auto& lhs: l.polynomials)
393  if (ls_.is_one(lhs.first))
394  ps_.add_here(res.polynomials[lhs.first],
395  ps_.conjunction(lhs.second,
396  ps_.lweight(r.constant, ps_.one())));
397 
398  // Label one from the rhs.
399  {
400  auto i = r.polynomials.find(one);
401  if (i != std::end(r.polynomials))
402  for (const auto& lhs: l.polynomials)
403  if (!ls_.is_one(lhs.first))
404  ps_.add_here(res.polynomials[one],
405  conjunction(ps_.lmul_label(rs_.atom(lhs.first),
406  lhs.second),
407  i->second));
408  }
409  }
410 
414  template <typename LabelSet = labelset_t, typename Conjunction>
416  Conjunction conjunction) const
417  -> std::enable_if_t<detail::is_letterized_t<LabelSet>{},
418  value_t>
419  {
420  auto res = value_t{ws_.mul(l.constant, r.constant)};
421  for (const auto& p: zip_maps(l.polynomials, r.polynomials))
422  res.polynomials[p.first]
423  = conjunction(std::get<0>(p.second), std::get<1>(p.second));
424 
427  normalize(res);
428  return res;
429  }
430 
434  template <typename LabelSet = labelset_t, typename Conjunction>
435  auto conjunction_(const value_t& lhs, const value_t& rhs,
436  Conjunction conjunction) const
437  -> std::enable_if_t<!detail::is_letterized_t<LabelSet>{},
438  value_t>
439  {
440  auto res = value_t{ws_.mul(lhs.constant, rhs.constant)};
441  for (const auto& l: lhs.polynomials)
442  for (const auto& r: rhs.polynomials)
443  {
444  // The longest common prefix.
445  auto lcp = ls_.lgcd(l.first, r.first);
446  if (!ls_.is_one(lcp))
447  {
448  auto left = rs_.atom(ls_.ldivide(lcp, l.first));
449  auto right = rs_.atom(ls_.ldivide(lcp, r.first));
450  ps_.add_here(res.polynomials[lcp],
451  conjunction(ps_.lmul_label(left, l.second),
452  ps_.lmul_label(right, r.second)));
453  }
454  }
455  normalize(res);
456  return res;
457  }
458 
460  template <typename Shuffle>
462  const value_t& lhs_xpn, const expression_t& lhs_xpr,
463  const value_t& rhs_xpn, const expression_t& rhs_xpr,
464  Shuffle shuffle) const
465  {
466  // (i) lhs_xpn:rhs_xpr.
467  for (const auto& p: lhs_xpn.polynomials)
468  for (const auto& m: p.second)
469  ps_.add_here(res.polynomials[p.first],
470  shuffle(label_of(m), rhs_xpr), weight_of(m));
471  // (ii) lhs_xpr:rhs_xpn
472  for (const auto& p: rhs_xpn.polynomials)
473  for (const auto& m: p.second)
474  ps_.add_here(res.polynomials[p.first],
475  shuffle(lhs_xpr, label_of(m)), weight_of(m));
476  // FIXME: normalize?
477  return res;
478  }
479 
480  public:
482  value_t conjunction(const value_t& l, const value_t& r) const
483  {
484  return conjunction_(l, r,
485  [this](const polynomial_t& l,
486  const polynomial_t& r)
487  {
488  return ps_.conjunction(l, r);
489  });
490  }
491 
495  value_t shuffle(const value_t& de, const expression_t& e,
496  const value_t& df, const expression_t& f) const
497  {
498  auto res = value_t{ws_.mul(de.constant, df.constant)};
499  return shuffle_(res,
500  de, e, df, f,
501  [this](const expression_t& l, const expression_t& r)
502  {
503  return rs_.shuffle(l, r);
504  });
505  }
506 
508  value_t infiltrate(const value_t& de, const expression_t& e,
509  const value_t& df, const expression_t& f) const
510  {
511  // Conjunction part: de&:df.
512  auto res =
513  conjunction_(de, df,
514  [this](const polynomial_t& l, const polynomial_t& r)
515  {
516  return ps_.infiltrate(l, r);
517  });
518 
519  // Shuffle part: de&:f + e&:df.
520  shuffle_(res,
521  de, e, df, f,
522  [this](const expression_t& l, const expression_t& r)
523  {
524  return rs_.infiltrate(l, r);
525  });
526  // FIXME: normalize?
527  return res;
528  }
529 
530  /*--------------.
531  | complement. |
532  `--------------*/
533 
535  value_t complement(const value_t& v) const
536  {
537  // We need an expansion whose firsts are letters. However,
538  // requiring a free labelset, i.e., rulling out lan, is too
539  // demanding, since, for instance, to compute {\} requires lan
540  // instead of lal.
541  //
542  // So require a letterized labelset.
543  return complement_<detail::is_letterized_t<labelset_t>{}>(v);
544  }
545 
546  private:
548  template <bool IsLetterized>
549  std::enable_if_t<!IsLetterized, value_t>
550  complement_(const value_t&) const
551  {
552  raise(me(),
553  ": complement: labelset must be letterized: ", ls_);
554  }
555 
557  template <bool IsLetterized>
558  std::enable_if_t<IsLetterized, value_t>
559  complement_(const value_t& v) const
560  {
561  auto res = value_t{ws_.is_zero(v.constant) ? ws_.one() : ws_.zero()};
562 
563  detail::static_if<labelset_t::has_one()>
564  ([this](const auto& v, const auto& ls)
565  {
566  require(!has(v.polynomials, ls.one()),
567  me(), ": complement: expansion must be normalized: ",
568  to_string(*this, v));
569  })(v, ls_);
570 
571  // Turn the polynomials into expressions, and complement them.
572  // The static-if is made of oneset.
573  detail::static_if<detail::has_generators_mem_fn<labelset_t>{}>
574  ([this, &res](const auto& v, const auto& ls)
575  {
576  for (auto l: ls.generators())
577  {
578  auto i = v.polynomials.find(l);
579  res.polynomials[l] =
580  ps_.complement(i == end(v.polynomials)
581  ? ps_.zero() : i->second);
582  }
583  })(v, ls_);
584  return res;
585  }
586 
587  /*-----------.
588  | ldivide. |
589  `-----------*/
590 
591  public:
593  value_t transpose(const value_t& v) const
594  {
595  auto res = value_t{ws_.transpose(v.constant)};
596  for (const auto& p: v.polynomials)
597  {
598  VCSN_REQUIRE(ls_.is_one(p.first),
599  *this, ": cannot transpose an expansion "
600  "with proper firsts: ", to_string(*this, v));
601  res.polynomials[p.first] = ps_.transpose(p.second);
602  }
603  return res;
604  }
605 
606  value_t ldivide(value_t lhs, value_t rhs) const
607  {
608  denormalize(lhs);
609  denormalize(rhs);
610  auto res = value_t{ws_.mul(lhs.constant, rhs.constant)};
611  auto one = detail::label_one(ls_);
612  auto& res_one = res.polynomials[one];
613 
614  // ε⊙[X_a \ Y_a + ...] for common firsts, included ε.
615  for (const auto& p: zip_maps(lhs.polynomials, rhs.polynomials))
616  ps_.add_ldivide_here(res_one,
617  std::get<0>(p.second),
618  std::get<1>(p.second));
619 
620  // If ε ∈ f(X) then ε⊙[X_ε \ (b Y_b) + ...]
621  if (has(lhs.polynomials, one))
622  for (const auto& rhsp: rhs.polynomials)
623  if (!ls_.is_one(rhsp.first))
624  ps_.add_ldivide_here(res_one,
625  lhs.polynomials[one],
626  ps_.lmul_label(rs_.atom(rhsp.first),
627  rhsp.second));
628 
629  // If ε ∈ f(Y) then ε⊙[(a X_a) \ Y_ε + ...]
630  if (has(rhs.polynomials, one))
631  for (const auto& lhsp: lhs.polynomials)
632  if (!ls_.is_one(lhsp.first))
633  ps_.add_ldivide_here(res_one,
634  ps_.lmul_label(rs_.atom(lhsp.first),
635  lhsp.second),
636  rhs.polynomials[one]);
637 
638  // It was handy to use res_one, but if it's zero, then remove it.
639  if (ps_.is_zero(res_one))
640  res.polynomials.erase(one);
641  normalize(res);
642  return res;
643  }
644 
645  public:
647  value_t
648  determinize(const value_t& v) const
649  {
650  auto res = value_t{v.constant};
651  for (const auto& lp: v.polynomials)
652  res.polynomials[lp.first] = {ps_.determinize(lp.second)};
653  return res;
654  }
655 
656  /*---------------.
657  | tuple(v...). |
658  `---------------*/
659 
661  template <unsigned Tape>
662  using project_t
664 
666  template <unsigned Tape>
667  auto project() const
668  -> project_t<Tape>
669  {
670  return {rs_.template project<Tape>()};
671  }
672 
674  template <typename... Expansions>
675  struct tuple_impl
676  {
679  template <size_t Tape>
680  auto denormalize_tape(const typename project_t<Tape>::value_t& e) const
681  -> typename project_t<Tape>::polys_t
682  {
683  auto es = eset_.template project<Tape>();
684  auto res = e;
685  es.denormalize(res);
686  VCSN_REQUIRE(es.expressionset().weightset()->is_zero(res.constant),
687  es, ": to-expansion: cannot denormalize ",
688  to_string(es, res),
689  ", need support for label one (the empty label)");
690  return res.polynomials;
691  }
692 
694  template <size_t... Tape>
695  auto denormalize(std::tuple<const Expansions&...>& es,
697  -> std::tuple<typename project_t<Tape>::polys_t...>
698  {
699  using res_t = std::tuple<typename project_t<Tape>::polys_t...>;
700  return res_t{denormalize_tape<Tape>(std::get<Tape>(es))...};
701  }
702 
704  auto denormalize(const Expansions&... es) const
705  {
706  auto t = std::tuple<const Expansions&...>{es...};
707  constexpr auto indices
708  = detail::make_index_sequence<sizeof...(Expansions)>{};
709  return denormalize(t, indices);
710  }
711 
712  auto
713  tuple(Expansions&&... es) const
714  -> value_t
715  {
716  auto res = eset_.zero();
717  auto polys = denormalize(std::forward<Expansions>(es)...);
719  ([&res, this](const auto&... ps)
720  {
721  auto l = label_t{ps.first...};
722  eset_.ps_.add_here(res.polynomials[l],
723  eset_.ps_.tuple(ps.second...));
724  },
725  polys);
727  return res;
728  }
729 
731  };
732 
786  template <typename... Expansions>
787  auto
788  tuple(Expansions&&... es) const
789  -> value_t
790  {
791  auto t = tuple_impl<Expansions...>{*this};
792  return t.tuple(std::forward<Expansions>(es)...);
793  }
794 
796  template <size_t Tape>
797  auto project(const value_t& v) const
798  {
799  auto xs = project<Tape>();
800  const auto& ps = xs.polynomialset();
801  using res_t = typename decltype(xs)::value_t;
802  auto res = res_t{};
803  res.constant = v.constant;
804  for (const auto& p: v.polynomials)
805  ps.add_here(res.polynomials[ls_.template project<Tape>(p.first)],
806  ps_.template project<Tape>(p.second));
807  // We might generate denormalized expansions, e.g., when
808  // projecting the expansion of `\e|a`, `\e` is a label.
809  xs.normalize(res);
810  return res;
811  }
812 
813  void
815  const value_t&, const value_t&,
816  std::false_type) const
817  {}
818 
819  void
821  const value_t& l, const value_t& r,
822  std::true_type) const
823  {
824  if (old_way_)
825  return compose_with_one_old_(res, l, r);
826  else
827  return compose_with_one_new_(res, l, r);
828  }
829 
830  void
832  const value_t& l, const value_t& r) const
833  {
834  assert(ws_.is_zero(l.constant));
835  assert(ws_.is_zero(r.constant));
836  const auto& ls0 = ls_.template set<0>();
837  const auto& ls1 = ls_.template set<1>();
838 
839  // Handle lhs labels with one on the second tape.
840  for (const auto& lhs: l.polynomials)
841  if (ls1.is_one(std::get<1>(lhs.first)))
842  for (const auto& rhs: r.polynomials)
843  if (!ls0.is_one(std::get<0>(rhs.first)))
844  // a|\e . [P1] @ b|c . [P2] becomes a|\e . [P1 @ (b|c)P2]
845  ps_.add_here(res.polynomials[lhs.first],
846  ps_.compose(lhs.second,
847  ps_.lmul_label(rs_.atom(rhs.first),
848  rhs.second)));
849  // Handle rhs labels with one on the first tape.
850  for (const auto& rhs: r.polynomials)
851  if (ls0.is_one(std::get<0>(rhs.first)))
852  for (const auto& lhs: l.polynomials)
853  if (!ls1.is_one(std::get<1>(lhs.first)))
854  // a|b . [P1] @ \e|c . [P2] becomes \e|c . [(a|b)P1 @ P2]
855  ps_.add_here(res.polynomials[rhs.first],
856  ps_.compose(ps_.lmul_label(rs_.atom(lhs.first),
857  lhs.second),
858  rhs.second));
859  }
860 
861  void
863  const value_t& l, const value_t& r) const
864  {
865  const auto& ls0 = ls_.template set<0>();
866  const auto& ls1 = ls_.template set<1>();
867 
868  // Handle lhs labels with one on the second tape.
869  for (const auto& lhs: l.polynomials)
870  if (ls1.is_one(std::get<1>(lhs.first)))
871  for (const auto& rhs: r.polynomials)
872  if (!ls0.is_one(std::get<0>(rhs.first)))
873  // a|\e . [P1] @ b|c . [P2] becomes a|c . [P1 @ (b|\e)P2]
874  {
875  // a|c.
876  auto l0 = ls_.tuple(ls_.template project<0>(lhs.first),
877  ls_.template project<1>(rhs.first));
878  // b|\e.
879  auto l1 = ls_.tuple(ls_.template project<0>(rhs.first),
880  ls_.template project<1>(lhs.first));
881  ps_.add_here(res.polynomials[l0],
882  ps_.compose(lhs.second,
883  ps_.lmul_label(rs_.atom(l1),
884  rhs.second)));
885  }
886  // Left constant.
887  //
888  // `$|$ . [<k>1] @ \e|c . [P2]` => `$|c . [(\e|$)<k>1 @ P2]`
889  // `<k> @ \e|c . [P2]` => `\e|c . [<k>1 @ P2]`
890  if (!ws_.is_zero(l.constant))
891  for (const auto& rhs: r.polynomials)
892  if (ls0.is_one(std::get<0>(rhs.first)))
893  ps_.add_here(res.polynomials[rhs.first],
894  ps_.compose(ps_.lweight(l.constant, ps_.one()),
895  rhs.second));
896 
897  // Handle rhs labels with one on the first tape.
898  for (const auto& rhs: r.polynomials)
899  if (ls0.is_one(std::get<0>(rhs.first)))
900  for (const auto& lhs: l.polynomials)
901  if (!ls1.is_one(std::get<1>(lhs.first)))
902  // a|b . [P1] @ \e|c . [P2] becomes a|c . [(\e|b)P1 @ P2]
903  {
904  // a|c.
905  auto l0 = ls_.tuple(ls_.template project<0>(lhs.first),
906  ls_.template project<1>(rhs.first));
907  // \e|b.
908  auto l1 = ls_.tuple(ls_.template project<0>(rhs.first),
909  ls_.template project<1>(lhs.first));
910  ps_.add_here(res.polynomials[l0],
911  ps_.compose(ps_.lmul_label(rs_.atom(l1),
912  lhs.second),
913  rhs.second));
914  }
915 
916  // Right constant.
917  //
918  // `a|\e . [P1] @ $|$ . [<k>1] ` => `a|$ . [P1 @ ($|\e)<k>1]`
919  // `a|\e . [P1] @ <k>` => `a|\e . [P1 @ <k>1]`.
920  if (!ws_.is_zero(r.constant))
921  for (const auto& lhs: l.polynomials)
922  if (ls0.is_one(std::get<1>(lhs.first)))
923  ps_.add_here(res.polynomials[lhs.first],
924  ps_.compose(lhs.second,
925  ps_.lweight(r.constant, ps_.one())));
926  }
927 
928 
930  template <typename Ctx = context_t>
931  auto compose(value_t l, value_t r) const
932  -> std::enable_if_t<are_composable<Ctx, Ctx>()
934  value_t>
935  {
936  // Tape of the lhs on which we compose.
937  constexpr auto out = labelset_t::size() - 1;
938  // Tape of the rhs on which we compose.
939  constexpr auto in = 0;
940  if (denorm_)
941  {
942  denormalize(l);
943  denormalize(r);
944  }
945  auto res = value_t{ws_.mul(l.constant, r.constant)};
946  for (const auto& lm: l.polynomials)
947  for (const auto& rm: r.polynomials)
948  if (ls_.template set<out>().equal(std::get<out>(label_of(lm)),
949  std::get<in>(label_of(rm))))
950  {
951  auto l = ls_.compose(ls_, label_of(lm),
952  ls_, label_of(rm));
953  ps_.add_here(res.polynomials[l],
954  ps_.compose(lm.second, rm.second));
955  }
958  // Beware that we might have introduced some constant terms
959  // (e.g., \e|x @ x|\e), and some polynomials equal to 0 (\e|x @ y|\e).
960  normalize(res);
961  return res;
962  }
963 
964 
965  private:
969  const labelset_t& ls_ = *rs_.labelset();
971  const weightset_t& ws_ = *rs_.weightset();
975  bool old_way_ = !!getenv("VCSN_OLDWAY");
977  bool denorm_ = old_way_ || !!getenv("VCSN_DENORM");
978  };
979  }
980 
981  template <typename Context>
984  {
985  return {es};
986  }
987 
988  namespace detail
989  {
991  template <typename Ctx1, typename Ctx2>
994  {
996 
998  const expansionset<expressionset<Ctx2>>& rhs)
999  {
1000  return type(vcsn::join(lhs.expressionset(), rhs.expressionset()));
1001  }
1002  };
1003  }
1004 }
auto denormalize(std::tuple< const Expansions &... > &es, detail::index_sequence< Tape... >) const -> std::tuple< typename project_t< Tape >::polys_t... >
Denormalize on all these tapes.
value_t & denormalize(value_t &res) const
Move the constant to the polynomial associated to one.
Print as a parsable type string.
Definition: format.hh:26
weightset_t_of< expressionset_t > weightset_t
Definition: expansionset.hh:30
auto project() const -> project_t< Tape >
The expansionset for tape Tape.
ATTRIBUTE_PURE bool has(const boost::container::flat_set< Key, Compare, Allocator > &s, const Key &e)
Whether e is member of s.
Definition: setalpha.hh:26
void compose_with_one_old_(value_t &res, const value_t &l, const value_t &r) const
value_t & normalize(value_t &res) const
Normalize: eliminate null polynomials and move the constant term from the label one.
typename detail::weightset_t_of_impl< base_t< ValueSet > >::type weightset_t_of
Definition: traits.hh:67
bool denorm_
Denormalize if requested explicitly, or if running the old way.
std::enable_if_t<!IsLetterized, value_t > complement_(const value_t &) const
Complement on an invalid labelset.
value_t complement(const value_t &v) const
The complement of v.
Denormalize a pack of one-tape expansions.
typename expressionset_t::value_t expression_t
Definition: expansionset.hh:29
size_t size(const ExpSet &rs, const typename ExpSet::value_t &r)
void cross_tuple(Fun f, const std::tuple< Ts... > &ts)
Definition: tuple.hh:347
auto label_one(const LabelSet &ls) -> typename LabelSet::value_t
Enjoy type inference.
Definition: labelset.hh:54
zipped_maps< Dereference, Maps... > zip_maps(Maps &&... maps)
Definition: zip-maps.hh:250
value_t & normalize_(value_t &res, std::true_type) const
Normalize res.
expansionset(const expressionset_t &rs)
Definition: expansionset.hh:53
auto tuple(Expansions &&... es) const -> value_t
The tuplization of single-tape expansions into a multitape expansion.
An inner node with multiple children.
Definition: expression.hh:119
value_t & rmul_label_here(value_t &res, const expression_t &rhs) const
In place right multiplication by an expression.
const weightset_t & ws_
Shorthand to the weightset.
std::map< label_t, polynomial_t, vcsn::less< labelset_t > > polys_t
Definition: expansionset.hh:42
void compose_with_one_(value_t &, const value_t &, const value_t &, std::false_type) const
static value_t conv(self_t, const value_t &v)
Conversion from (this and) other weightsets.
auto conjunction_(const value_t &lhs, const value_t &rhs, Conjunction conjunction) const -> std::enable_if_t<!detail::is_letterized_t< LabelSet >
The conjunction of l and r.
const polynomialset_t & polynomialset() const
The polynomialset.
Definition: expansionset.hh:72
typename weightset_t::value_t weight_t
Definition: expansionset.hh:31
auto denormalize_tape(const typename project_t< Tape >::value_t &e) const -> typename project_t< Tape >::polys_t
Denormalize on this tape: from expansion to pure polynomial.
value_t & denormalize_(value_t &res, std::true_type) const
Denormalize res move the constant to the polynomial associated to one.
value_t conjunction(const value_t &l, const value_t &r) const
The conjunction of l and r.
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:21
value_t rweight(const value_t &lhs, const weight_t &w) const
Right-multiplication of lhs by w.
polynomialset_t ps_
The polynomialset for the polynomials.
const labelset_t & ls_
Shorthand to the labelset.
auto project(const value_t &v) const
Project a multitape expansion.
expressionset_t rs_
The expressionset used for the expressions.
std::ostream & print_set(std::ostream &o, format fmt={}) const
Print this valueset.
Definition: expansionset.hh:84
typename detail::context_t_of_impl< base_t< ValueSet > >::type context_t_of
Definition: traits.hh:61
Print as rich UTF-8 text, escaped.
Definition: format.hh:30
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
void conjunctions_with_one_(value_t &, const value_t &, const value_t &, std::false_type, Conjunction) const
bool old_way_
Whether to running the old composition code.
value_t add(value_t res, const value_t &rhs) const
Addition.
value_t & denormalize_(value_t &res, std::false_type) const
Denormalize when there is no label one: identity.
std::integral_constant< bool, B > bool_constant
Definition: type_traits.hh:12
auto join(const ValueSet &vs) -> ValueSet
The join of a single valueset.
Definition: join.hh:44
void erase_if(Container &c, Predicate p)
In place removal of entries matching the predicate.
Definition: algorithm.hh:55
auto denormalize(const Expansions &... es) const
Entry point: Denormalize all these expansions.
A structure that implements the computation of join(V1, V2).
Definition: join.hh:18
typename detail::labelset_t_of_impl< base_t< ValueSet > >::type labelset_t_of
Definition: traits.hh:63
value_t & lweight_here(const weight_t &w, value_t &res) const
Inplace left-multiplication by w of res.
Build the static sequence of size_t [0, N[.
Definition: tuple.hh:56
auto conjunction_(value_t l, value_t r, Conjunction conjunction) const -> std::enable_if_t< detail::is_letterized_t< LabelSet >
The conjunction of l and r.
value_t conv(const expansionset< OtherExpSet > &other, const typename expansionset< OtherExpSet >::value_t &v) const
Convert from another expansionset to self.
value_t one() const
The one.
typename polynomialset_t::monomial_t monomial_t
Definition: expansionset.hh:35
Definition: a-star.hh:8
auto in(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions arriving to state s.
Definition: automaton.hh:135
std::enable_if_t< IsLetterized, value_t > complement_(const value_t &v) const
Complement on a letterized labelset.
std::ostream & print(const value_t &v, std::ostream &o=std::cout, format fmt={}) const
Print this expansion.
std::string type(const automaton &a)
The implementation type of a.
Definition: others.cc:238
context_t_of< expressionset_t > context_t
Definition: expansionset.hh:26
typename detail::label_t_of_impl< base_t< ValueSet > >::type label_t_of
Definition: traits.hh:62
value_t & normalize_(value_t &res, std::false_type) const
Normalize when there is no label one: identity.
expansionset< expressionset< Context > > make_expansionset(const expressionset< Context > &es)
auto tuple(Expansions &&... es) const -> value_t
labelset_t_of< context_t > labelset_t
Definition: expansionset.hh:27
Print as plain (ASCII) text, escaped.
Definition: format.hh:28
value_t lweight(const weight_t &w, value_t res) const
Left-multiplication by w of rhs.
void weight_set(welement< Label, Weight > &m, const Weight &w)
Set the weight of a welement.
Definition: wet.hh:162
static constexpr const char * me()
Definition: expansionset.hh:37
std::string to_string(identities i)
Wrapper around operator<<.
Definition: identities.cc:38
void compose_with_one_new_(value_t &res, const value_t &l, const value_t &r) const
A static list of size_t.
Definition: tuple.hh:32
value_t zero() const
The zero.
auto weight_of(const welement< Label, Weight > &m) -> decltype(m.weight())
The weight of a welement.
Definition: wet.hh:154
return v
Definition: multiply.hh:362
auto label_of(const welement< Label, Weight > &m) -> decltype(m.label())
The label of a welement.
Definition: wet.hh:146
value_t ldivide(value_t lhs, value_t rhs) const
symbol sname()
Definition: name.hh:65
Print as is. For instance, don&#39;t try to escape labels.
Definition: format.hh:24
Print for LaTeX.
Definition: format.hh:22
value_t & shuffle_(value_t &res, const value_t &lhs_xpn, const expression_t &lhs_xpr, const value_t &rhs_xpn, const expression_t &rhs_xpr, Shuffle shuffle) const
The shuffle product of l and r.
void compose_with_one_(value_t &res, const value_t &l, const value_t &r, std::true_type) const
expression_polynomialset_t< ExpSet > make_expression_polynomialset(const ExpSet &rs)
From a ExpSet to its polynomialset.
Definition: split.hh:31
value_t shuffle(const value_t &de, const expression_t &e, const value_t &df, const expression_t &f) const
The shuffle product of de and df.
static type join(const expansionset< expressionset< Ctx1 >> &lhs, const expansionset< expressionset< Ctx2 >> &rhs)
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:87
value_t transpose(const value_t &v) const
Transpose an expansion. The firsts must be reduced to one.
value_t infiltrate(const value_t &de, const expression_t &e, const value_t &df, const expression_t &f) const
The infiltration product of l and r.
value_t determinize(const value_t &v) const
Turn the polynomials into (normalized) monomials.
auto compose(value_t l, value_t r) const -> std::enable_if_t< are_composable< Ctx, Ctx >() &&number_of_tapes< Ctx >::value==2, value_t >
The composition of l and r.
static symbol sname()
The static name.
Definition: expansionset.hh:58
bool is_normal(const value_t &x) const
Whether an expansion is normal.
const context_t & context() const
The context.
Definition: expansionset.hh:78
typename polynomialset_t::value_t polynomial_t
Definition: expansionset.hh:34
#define VCSN_REQUIRE(Cond,...)
A macro similar to require.
Definition: raise.hh:98
void conjunctions_with_one_(value_t &res, const value_t &l, const value_t &r, std::true_type, Conjunction conjunction) const
value_t & ldivide_here(const weight_t &w, value_t &res) const
Inplace left-division by w of res.
const expressionset_t & expressionset() const
The expressionset.
Definition: expansionset.hh:66
value_t atom(const label_t &l) const
A single label.
void add_here(value_t &lhs, const value_t &rhs) const
In place addition.
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:86