Vcsn  2.8
Be Rational
polynomialset.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <algorithm>
4 #include <iostream>
5 #include <sstream>
6 #include <type_traits>
7 #include <vector>
8 
9 #include <boost/optional.hpp>
10 #include <boost/range/algorithm/equal.hpp>
11 #include <boost/range/algorithm/find_if.hpp>
12 #include <boost/range/algorithm/lexicographical_compare.hpp>
13 
14 #include <vcsn/ctx/context.hh> // We need context to define join.
16 #include <vcsn/ctx/traits.hh>
17 #include <vcsn/misc/algorithm.hh> // front
18 #include <vcsn/misc/attributes.hh>
19 #include <vcsn/misc/functional.hh>
20 #include <vcsn/misc/math.hh>
21 #include <vcsn/misc/raise.hh>
22 #include <vcsn/misc/star-status.hh>
23 #include <vcsn/misc/static-if.hh>
24 #include <vcsn/misc/stream.hh>
25 #include <vcsn/misc/wet.hh>
26 #include <vcsn/misc/zip-maps.hh>
27 #include <vcsn/weightset/f2.hh>
28 #include <vcsn/weightset/fwd.hh>
29 #include <vcsn/weightset/z.hh>
30 
31 namespace vcsn
32 {
33  namespace detail
34  {
35  /*-----------------.
36  | label_is_zero. |
37  `-----------------*/
38 
40  template <typename LabelSet>
41  using zero_mem_fn_t
42  = decltype(std::declval<LabelSet>().zero());
43 
45  template <typename LabelSet>
47 
48  template <typename LabelSet>
49  auto label_is_zero(const LabelSet& ls, const typename LabelSet::value_t& l)
50  {
51  return detail::static_if<has_zero_mem_fn<LabelSet>{}>
52  ([](const auto& ls, const auto& l){ return ls.is_zero(l);},
53  [](const auto&, const auto&) { return false; })
54  (ls, l);
55  }
56 
57  /*--------------------.
58  | is_division_ring. |
59  `--------------------*/
60 
61  template <typename WeightSet>
63  : std::true_type
64  {};
65 
66  template <>
68  : std::false_type
69  {};
70 
71  template <typename Context, wet_kind_t Kind>
72  struct is_division_ring<polynomialset<Context, Kind>>
73  : std::false_type
74  {};
75 
78  template <typename Context, wet_kind_t Kind>
79  class polynomialset_impl
80  {
81  public:
83  using context_t = Context;
86 
87  using labelset_ptr = typename context_t::labelset_ptr;
88  using weightset_ptr = typename context_t::weightset_ptr;
90  using label_t = typename labelset_t::value_t;
92 
95  using monomial_t = typename value_t::value_type;
96 
97  polynomialset_impl() = delete;
98  polynomialset_impl(const polynomialset_impl&) = default;
101  : ctx_{ctx}
102  {}
103 
114  const self_t& self() const { return static_cast<const self_t&>(*this); }
115 
117  static symbol sname()
118  {
119  static auto res = symbol{"polynomialset<" + context_t::sname() + '>'};
120  return res;
121  }
122 
123  const context_t& context() const { return ctx_; }
124  const labelset_ptr& labelset() const { return ctx_.labelset(); }
125  const weightset_ptr& weightset() const { return ctx_.weightset(); }
126 
127  static constexpr bool is_commutative() { return false; }
128  static constexpr bool has_lightening_weights()
129  {
130  return weightset_t::has_lightening_weights();
131  }
132 
134  value_t value(const label_t& l, const weight_t w) const
135  {
136  return value_t{{l, w}};
137  }
138 
140  value_t&
141  del_weight(value_t& v, const label_t& l) const
142  {
143  v.erase(l);
144  return v;
145  }
146 
149  value_t&
150  new_weight(value_t& v, const label_t& l, const weight_t w) const
151  {
152  assert(!weightset()->is_zero(w));
153  v.set(l, w);
154  return v;
155  }
156 
158  value_t&
159  set_weight(value_t& v, const label_t& l, const weight_t w) const
160  {
161  if (weightset()->is_zero(w))
162  return del_weight(v, l);
163  else
164  return new_weight(v, l, w);
165  }
166 
167  const weight_t
168  get_weight(const value_t& v, const label_t& l) const ATTRIBUTE_PURE
169  {
170  auto i = v.find(l);
171  if (i == v.end())
172  return weightset()->zero();
173  else
174  return weight_of(*i);
175  }
176 
177 
178  /*---------.
179  | clear. |
180  `---------*/
181 
183  void clear(value_t& v)
184  {
185  v.clear();
186  }
187 
188 
189  /*-------.
190  | add. |
191  `-------*/
192 
194  value_t&
195  add_here(value_t& v, const label_t& l, const weight_t k) const
196  {
197  if (!label_is_zero(*labelset(), l))
198  {
199  auto i = v.find(l);
200  if (i == v.end())
201  set_weight(v, l, k);
202  else
203  {
204  // Do not use set_weight() because it would lookup l
205  // again and we already have the right iterator.
206  auto w2 = weightset()->add(weight_of(*i), k);
207  if (weightset()->is_zero(w2))
208  v.erase(i);
209  else
210  v.set(i, w2);
211  }
212  }
213  return v;
214  }
215 
217  value_t&
218  add_here(value_t& v, const monomial_t& m) const
219  {
220  return add_here(v, label_of(m), weight_of(m));
221  }
222 
224  template <wet_kind_t WetType, typename WS>
225  auto
226  add_here_impl_(value_t& l, const value_t& r) const
227  -> std::enable_if_t<WetType != wet_kind_t::bitset,
228  value_t&>
229  {
230  for (const auto& m: r)
231  add_here(l, m);
232  return l;
233  }
234 
236  template <wet_kind_t WetType, typename WS>
237  auto
238  add_here_impl_(value_t& l, const value_t& r) const
239  -> std::enable_if_t<(WetType == wet_kind_t::bitset
240  && std::is_same<WS, b>::value),
241  value_t&>
242  {
243  l.set() |= r.set();
244  return l;
245  }
246 
248  template <wet_kind_t WetType, typename WS>
249  auto
250  add_here_impl_(value_t& l, const value_t& r) const
251  -> std::enable_if_t<(WetType == wet_kind_t::bitset
252  && std::is_same<WS, f2>::value),
253  value_t&>
254  {
255  l.set() ^= r.set();
256  return l;
257  }
258 
259  value_t&
260  add_here(value_t& l, const value_t& r) const
261  {
262  return add_here_impl_<value_t::kind, weightset_t>(l, r);
263  }
264 
266  value_t add(value_t res, const value_t& r) const
267  {
268  add_here(res, r);
269  return res;
270  }
271 
272 
273  /*-------.
274  | sub. |
275  `-------*/
276 
278  value_t&
279  sub_here(value_t& v, const monomial_t& m) const
280  {
281  if (!label_is_zero(*labelset(), label_of(m)))
282  {
283  auto i = v.find(label_of(m));
284  if (i == v.end())
285  {
286  raise(*this, ": sub_here: invalid arguments: ",
287  to_string(*this, v), ", ", to_string(*this, m));
288  }
289  else
290  {
291  // Do not use set_weight() because it would lookup w
292  // again and we already have the right iterator.
293  auto w2 = weightset()->sub(weight_of(*i), weight_of(m));
294  if (weightset()->is_zero(w2))
295  v.erase(i);
296  else
297  weight_set(*i, w2);
298  }
299  }
300  return v;
301  }
302 
304  value_t
305  sub(const value_t& l, const value_t& r) const
306  {
307  auto res = l;
308  for (const auto& rm: r)
309  sub_here(res, rm);
310  return res;
311  }
312 
313 
314  /*-------.
315  | mul. |
316  `-------*/
317 
319  monomial_t
320  mul(const monomial_t& l, const monomial_t& r) const
321  {
322  return {labelset()->mul(label_of(l), label_of(r)),
323  weightset()->mul(weight_of(l), weight_of(r))};
324  }
325 
328  template <wet_kind_t WetType>
329  auto
330  mul_impl_(const value_t& l, const value_t& r) const
331  -> std::enable_if_t<WetType != wet_kind_t::bitset,
332  value_t>
333  {
334  auto res = value_t{};
335  for (const auto& lm: l)
336  for (const auto& rm: r)
337  add_here(res,
338  labelset()->mul(label_of(lm), label_of(rm)),
339  weightset()->mul(weight_of(lm), weight_of(rm)));
340  return res;
341  }
342 
345  template <wet_kind_t WetType>
346  auto
347  mul_impl_(const value_t& l, const value_t& r) const
348  -> std::enable_if_t<WetType == wet_kind_t::bitset,
349  value_t>
350  {
351  return l.set() & r.set();
352  }
353 
355  auto
356  mul(const value_t& l, const value_t& r) const
357  -> value_t
358  {
359  return mul_impl_<value_t::kind>(l, r);
360  }
361 
363  auto
364  mul(const value_t& p, const label_t& l, const weight_t w) const
365  -> value_t
366  {
367  auto res = value_t{};
368  for (const auto& m: p)
369  add_here(res,
370  labelset()->mul(label_of(m), l),
371  weightset()->mul(weight_of(m), w));
372  return res;
373  }
374 
375 
376  /*---------------.
377  | conjunction. |
378  `---------------*/
379 
382  template <typename Ctx>
383  std::enable_if_t<Ctx::is_lar, value_t>
384  conjunction_impl_(const value_t& l, const value_t& r) const
385  {
386  auto res = value_t{};
387  for (const auto& lm: l)
388  for (const auto& rm: r)
389  add_here(res,
390  labelset()->conjunction(label_of(lm), label_of(rm)),
391  weightset()->mul(weight_of(lm), weight_of(rm)));
392  return res;
393  }
394 
397  template <typename Ctx>
398  std::enable_if_t<!Ctx::is_lar, value_t>
399  conjunction_impl_(const value_t& l, const value_t& r) const
400  {
401  auto res = value_t{};
402  for (const auto& p: zip_maps<vcsn::as_tuple>(l, r))
403  add_here(res,
404  label_of(std::get<0>(p)),
405  weightset()->mul(weight_of(std::get<0>(p)),
406  weight_of(std::get<1>(p))));
407  return res;
408  }
409 
410  value_t
411  conjunction(const value_t& l, const value_t& r) const
412  {
413  return conjunction_impl_<context_t>(l, r);
414  }
415 
418  value_t
419  infiltrate(const value_t& l, const value_t& r) const
420  {
421  auto res = value_t{};
422  for (const auto& lm: l)
423  for (const auto& rm: r)
424  add_here(res,
425  labelset()->infiltrate(label_of(lm), label_of(rm)),
426  weightset()->mul(weight_of(lm), weight_of(rm)));
427  return res;
428  }
429 
432  template <wet_kind_t WetType = value_t::kind>
433  auto
434  scalar_product(const value_t& l, const value_t& r) const
435  -> std::enable_if_t<WetType != wet_kind_t::bitset,
436  weight_t>
437  {
438  auto res = weightset()->zero();
439  for (const auto& p: zip_maps<vcsn::as_tuple>(l, r))
440  res = weightset()->add(res,
441  weightset()->mul(weight_of(std::get<0>(p)),
442  weight_of(std::get<1>(p))));
443  return res;
444  }
445 
448  template <wet_kind_t WetType = value_t::kind, typename WS = weightset_t>
449  auto
450  scalar_product(const value_t& l, const value_t& r) const
451  -> std::enable_if_t<(WetType == wet_kind_t::bitset
452  && std::is_same<WS, b>::value),
453  weight_t>
454  {
455  return l.set().intersects(r.set());
456  }
457 
460  template <wet_kind_t WetType = value_t::kind, typename WS = weightset_t>
461  auto
462  scalar_product(const value_t& l, const value_t& r) const
463  -> std::enable_if_t<(WetType == wet_kind_t::bitset
464  && std::is_same<WS, f2>::value),
465  weight_t>
466  {
467  return (l.set() & r.set()).count() % 2;
468  }
469 
471  value_t abs(const value_t& v) const
472  {
473  auto res = value_t{};
474  for (const auto& m: v)
475  add_here(res, label_of(m), weightset()->abs(weight_of(m)));
476  return res;
477  }
478 
480  value_t
481  star(const value_t& v) const
482  {
483  // The only starrable polynomials are scalars (if they are
484  // starrable too).
485  auto s = v.size();
486  if (s == 0)
487  return one();
488  else if (s == 1)
489  {
490  auto i = v.find(labelset()->one());
491  if (i != v.end())
492  return {{i->first, weightset()->star(i->second)}};
493  }
494  raise_not_starrable(*this, v);
495  }
496 
498  value_t
499  lweight(const weight_t w, const value_t& v) const
500  {
501  auto res = value_t{};
502  if (weightset()->is_one(w))
503  res = v;
504  else if (!weightset()->is_zero(w))
505  for (const auto& m: v)
506  add_here(res, label_of(m), weightset()->mul(w, weight_of(m)));
507  return res;
508  }
509 
511  value_t
512  lmul_label(const label_t& lhs, const value_t& v) const
513  {
514  auto res = value_t{};
515  for (const auto& m: v)
516  add_here(res,
517  labelset()->mul(lhs, label_of(m)),
518  weight_of(m));
519  return res;
520  }
521 
523  value_t
524  mul(const monomial_t& lhs, const value_t& v) const
525  {
526  auto res = value_t{};
527  for (const auto& m: v)
528  add_here(res,
529  labelset()->mul(label_of(lhs), label_of(m)),
530  weightset()->mul(weight_of(lhs), weight_of(m)));
531  return res;
532  }
533 
535  template <typename Ctx>
536  using rweight_t
537  = decltype(std::declval<labelset_t_of<Ctx>>()
538  .rweight(std::declval<label_t_of<Ctx>>(),
539  std::declval<weight_t_of<Ctx>>()));
540 
542  template <typename Ctx>
544 
546  auto
547  rweight(const value_t& v, const weight_t w) const
548  -> value_t
549  {
550  auto res = value_t{};
551  if (weightset()->is_one(w))
552  res = v;
553  else if (!weightset()->is_zero(w))
554  for (const auto& m: v)
555  // Beware that if the labelset supports weights (e.g.,
556  // polynomial of expressions), we do not multiply the weight
557  // here, but the label.
558  static_if<has_rweight_fn<context_t>{}>
559  ([this, &res] (const auto& ls, const auto& m, const auto& w)
560  {
561  add_here(res,
562  ls.rweight(label_of(m), w),
563  weight_of(m));
564  },
565  [this, &res] (const auto&, const auto& m, const auto& w)
566  {
567  add_here(res,
568  label_of(m),
569  weightset()->mul(w, weight_of(m)));
570  })
571  (*labelset(), m, w);
572  return res;
573  }
574 
576  value_t
577  rmul_label(const value_t& v, const label_t& rhs) const
578  {
579  auto res = value_t{};
580  for (const auto& lhs: v)
581  add_here(res,
582  labelset()->mul(label_of(lhs), rhs),
583  weight_of(lhs));
584  return res;
585  }
586 
588  value_t
589  mul(const value_t& l, const monomial_t& rhs) const
590  {
591  auto res = value_t{};
592  for (const auto& lhs: l)
593  add_here(res,
594  labelset()->mul(label_of(lhs), label_of(rhs)),
595  weightset()->mul(weight_of(lhs), weight_of(rhs)));
596  return res;
597  }
598 
599  value_t
600  rdivide(const value_t& l, const value_t& r) const
601  {
602  raise(*this, ": rdivide: not implemented (",
603  to_string(*this, l), ", ", to_string(*this, r), ")");
604  }
605 
607  monomial_t
608  ldivide(const monomial_t& l, const monomial_t& r) const
609  {
610  return {labelset()->ldivide(label_of(l), label_of(r)),
611  weightset()->ldivide(weight_of(l), weight_of(r))};
612  }
613 
615  value_t
616  ldivide(const monomial_t& l, const value_t& r) const
617  {
618  auto res = value_t{};
619  for (const auto& m: r)
620  add_here(res, ldivide(l, m));
621  return res;
622  }
623 
626  template <typename Ctx = context_t>
627  std::enable_if_t<Ctx::is_lar, value_t&>
628  add_ldivide_here(value_t& res, const value_t& l, const value_t& r) const
629  {
630  for (const auto& lm: l)
631  for (const auto& rm: r)
632  // Our implementation of the {\} operator in the expressions
633  // requires that we *multiply* the weights, which is not
634  // what the division of monomials does. So don't use it.
635  // Don't change the division of monomials to use the
636  // multiplication though, or you would break simple things
637  // such as `poly('<2>\e') // poly('a+<2>b')` => `<1/2>a + b`.
638  // Actually, it would not even terminate.
639  add_here(res,
640  {labelset()->ldivide(label_of(lm), label_of(rm)),
641  weightset()->mul(weight_of(lm), weight_of(rm))});
642  return res;
643  }
644 
647  template <typename Ctx = context_t>
648  std::enable_if_t<!Ctx::is_lar, value_t&>
649  add_ldivide_here(value_t& res, const value_t& l, const value_t& r) const
650  {
651  if (is_zero(l))
652  raise(*this, ": ldivide: division by zero");
653  else
654  {
655  auto remainder = r;
656  while (!is_zero(remainder))
657  {
658  auto factor = ldivide(detail::front(l), detail::front(remainder));
659  add_here(res, factor);
660  remainder = sub(remainder, mul(l, factor));
661  }
662 
663  if (!is_zero(remainder))
664  raise(*this, ": ldivide: not implemented (",
665  to_string(*this, l), ", ", to_string(*this, r), ")");
666  }
667  return res;
668  }
669 
671  value_t
672  ldivide(const value_t& l, const value_t& r) const
673  {
674  auto res = value_t{};
675  add_ldivide_here(res, l, r);
676  return res;
677  }
678 
680  value_t&
681  ldivide_here(const weight_t w, value_t& v) const
682  {
683  if (!weightset()->is_one(w))
684  for (auto&& m: v)
685  weight_set(m, weightset()->ldivide(w, weight_of(m)));
686  return v;
687  }
688 
690  value_t&
691  rdivide_here(value_t& v, const weight_t w) const
692  {
693  if (!weightset()->is_one(w))
694  for (auto& m: v)
695  weight_set(m, weightset()->rdivide(weight_of(m), w));
696  return v;
697  }
698 
705  value_t lgcd(const value_t& lhs, const value_t& rhs) const
706  {
707  using std::begin;
708  using std::end;
709  auto res = value_t{};
710  // For each monomial, look for the matching GCD of the weight.
711  auto i = begin(lhs), i_end = end(lhs);
712  auto j = begin(rhs), j_end = end(rhs);
713  for (;
714  i != i_end && j != j_end
715  && labelset()->equal(i->first, j->first);
716  ++i, ++j)
717  res.set(i->first, weightset()->lgcd(i->second, j->second));
718  // If the sets of labels are different, the polynomials
719  // cannot be "colinear", and the GCD is just 1.
720  if (i != i_end || j != j_end)
721  res = one();
722  return res;
723  }
724 
725  /*--------.
726  | norm. |
727  `--------*/
728 
730  template <typename WeightSet, typename Dummy = void>
731  struct norm_
732  {
733  typename WeightSet::value_t operator()(const value_t& v) const
734  {
735  return weight_of(front(v));
736  }
737  const WeightSet& ws_;
738  };
739 
741  template <typename Dummy>
742  struct norm_<z, Dummy>
743  {
744  typename z::value_t operator()(const value_t& v) const
745  {
746  int sign = 0 < weight_of(detail::front(v)) ? 1 : -1;
747  auto res = std::abs(weight_of(detail::front(v)));
748  for (const auto& m: v)
749  res = z_.lgcd(res, std::abs(weight_of(m)));
750  res *= sign;
751  return res;
752  }
753  const z& z_;
754  };
755 
757  template <typename Ctx, wet_kind_t Knd, typename Dummy>
758  struct norm_<polynomialset<Ctx, Knd>, Dummy>
759  {
761 
762  typename ps_t::value_t operator()(const value_t& v) const
763  {
764  typename ps_t::value_t res = weight_of(detail::front(v));
765  for (const auto& p: v)
766  res = ps_.lgcd(res, weight_of(p));
767  return res;
768  }
769  const ps_t& ps_;
770  };
771 
774  auto norm(const value_t& v) const
775  -> weight_t
776  {
777  if (is_zero(v))
778  return weightset()->zero();
779  else
780  return norm_<weightset_t>{*weightset()}(v);
781  }
782 
783 
784  /*-------------.
785  | normalize. |
786  `-------------*/
787 
791  {
792  // Zero is in normal form, don't try to divide by zero.
793  auto res = norm(v);
794  if (!weightset()->is_zero(res))
795  ldivide_here(res, v);
796  return res;
797  }
798 
801  {
802  normalize_here(res);
803  return res;
804  }
805 
806 
807 
808  /*---------------.
809  | tuple(v...). |
810  `---------------*/
811 
814  template <typename... Polys>
815  auto
816  tuple(Polys&&... vs) const
817  -> value_t
818  {
819  auto res = value_t{};
820  detail::cross([&res, this](auto... ms)
821  {
822  this->add_here(res,
823  this->labelset()->tuple(ms.first...),
824  this->weightset()->mul(ms.second...));
825  },
826  std::forward<Polys>(vs)...);
827  return res;
828  }
829 
831  template <size_t Tape>
832  auto project() const
833  {
834  return make_polynomialset(vcsn::detail::project<Tape>(context()));
835  }
836 
838  template <size_t Tape>
839  auto project(const value_t& v) const
840  {
841  auto ps = project<Tape>();
842  auto res = ps.zero();
843  for (const auto& m: v)
844  ps.add_here(res,
845  labelset()->template project<Tape>(label_of(m)),
846  weight_of(m));
847  return res;
848  }
849 
850  /*-----------.
851  | compose. |
852  `-----------*/
853 
855  template <typename Ctx>
856  using compose_t
857  = decltype(std::declval<labelset_t_of<Ctx>>()
858  .compose(std::declval<label_t_of<Ctx>>(),
859  std::declval<label_t_of<Ctx>>()));
860 
863  template <typename Ctx>
865 
866 
869  template <typename Ctx1, typename Ctx2>
870  auto
872  const typename polynomialset<Ctx1>::value_t& p1,
873  const polynomialset<Ctx2>& ps2,
874  const typename polynomialset<Ctx2>::value_t& p2) const
875  -> std::enable_if_t<are_composable<Ctx1, Ctx2>{}, value_t>
876  {
877  const auto& ls = *labelset();
878  const auto& ls1 = *ps1.labelset();
879  const auto& ls2 = *ps2.labelset();
880  // Tape of the lhs on which we compose.
881  constexpr auto out = number_of_tapes<Ctx2>::value - 1;
882  // Tape of the rhs on which we compose.
883  constexpr auto in = 0;
884  // A labelset for the common tape type.
885  const auto& midls = ls1.template set<out>();
886  auto res = value_t{};
887  for (const auto& m1: p1)
888  for (const auto& m2: p2)
889  if (midls.equal(std::get<out>(label_of(m1)),
890  std::get<in>(label_of(m2))))
891  add_here(res,
892  ls.compose(ls1, label_of(m1),
893  ls2, label_of(m2)),
894  weightset()->mul(weight_of(m1), weight_of(m2)));
895  return res;
896  }
897 
900  template <typename Ctx = context_t>
901  auto
902  compose(const value_t& l, const value_t& r) const
903  -> std::enable_if_t<has_compose_fn<Ctx>{}, value_t>
904  {
905  auto res = value_t{};
906  for (const auto& lm: l)
907  for (const auto& rm: r)
908  add_here(res,
909  labelset()->compose(label_of(lm), label_of(rm)),
910  weightset()->mul(weight_of(lm), weight_of(rm)));
911  return res;
912  }
913 
914 
915 
922  label_t to_label(const value_t& v) const
923  {
924  label_t res = labelset()->zero();
925  for (const auto& m: v)
926  res = labelset()->add(res,
927  labelset()->lweight(weight_of(m), label_of(m)));
928  return res;
929  }
930 
935  {
936  weight_t w = normalize_here(v);
937  return {to_label(v), w};
938  }
939 
943  value_t complement(const value_t& v) const
944  {
945  return {{labelset()->complement(to_label(normalize(v))),
946  weightset()->one()}};
947  }
948 
949  /*---------------.
950  | equal(l, r). |
951  `---------------*/
952 
953  ATTRIBUTE_PURE
954  static bool monomial_equal(const monomial_t& lhs,
955  const monomial_t& rhs)
956  {
957  return (labelset_t::equal(label_of(lhs), label_of(rhs))
958  && weightset_t::equal(weight_of(lhs), weight_of(rhs)));
959  }
960 
961  template <wet_kind_t WetType>
962  ATTRIBUTE_PURE
963  static auto
964  equal_impl_(const value_t& l, const value_t& r)
965  -> std::enable_if_t<WetType != wet_kind_t::bitset,
966  bool>
967  {
968  return boost::equal(l, r, monomial_equal);
969  }
970 
971  template <wet_kind_t WetType>
972  ATTRIBUTE_PURE
973  static auto
974  equal_impl_(const value_t& l, const value_t& r)
975  -> std::enable_if_t<WetType == wet_kind_t::bitset,
976  bool>
977  {
978  return l.set() == r.set();
979  }
980 
982  ATTRIBUTE_PURE
983  static bool
984  equal(const value_t& l, const value_t& r)
985  {
986  return equal_impl_<value_t::kind>(l, r);
987  }
988 
990  static const value_t& one()
991  {
992  static auto res = value_t{monomial_one()};
993  return res;
994  }
995 
997  static const monomial_t& monomial_one()
998  {
999  static auto res = monomial_t{labelset_t::one(), weightset_t::one()};
1000  return res;
1001  }
1002 
1004  static bool is_one(const value_t& v) ATTRIBUTE_PURE
1005  {
1006  if (v.size() != 1)
1007  return false;
1008  auto i = v.find(labelset_t::one());
1009  if (i == v.end())
1010  return false;
1011  return weightset_t::is_one(i->second);
1012  }
1013 
1014  const value_t&
1015  zero() const
1016  {
1017  static auto res = value_t{};
1018  return res;
1019  }
1020 
1021  bool
1022  is_zero(const value_t& v) const
1023  {
1024  return v.empty();
1025  }
1026 
1027  static constexpr bool show_one() { return false; }
1028  static constexpr star_status_t star_status()
1029  {
1030  return weightset_t::star_status();
1031  }
1032 
1034  static value_t
1036  {
1037  return v;
1038  }
1039 
1043  template <typename WS>
1044  value_t
1045  conv(const WS& ws, const typename WS::value_t& v) const
1046  {
1047  return {{labelset()->one(), weightset()->conv(ws, v)}};
1048  }
1049 
1051  template <typename C, wet_kind_t K>
1052  value_t
1054  const typename polynomialset<C, K>::value_t& v) const
1055  {
1056  const typename C::labelset_t& sls = *sps.labelset();
1057  const typename C::weightset_t& sws = *sps.weightset();
1058  const labelset_t& tls = *labelset();
1059  const weightset_t& tws = *weightset();
1060  auto res = value_t{};
1061  for (const auto& m: v)
1062  add_here(res, tls.conv(sls, label_of(m)), tws.conv(sws, weight_of(m)));
1063  return res;
1064  }
1065 
1066 
1067  /*-----------------.
1068  | compare(l, r). |
1069  `-----------------*/
1070 
1071  ATTRIBUTE_PURE
1072  static int
1073  monomial_compare(const monomial_t& lhs, const monomial_t& rhs)
1074  {
1075  if (auto res = labelset_t::compare(label_of(lhs), label_of(rhs)))
1076  return res;
1077  else
1078  return weightset_t::compare(weight_of(lhs), weight_of(rhs));
1079  }
1080 
1081  template <wet_kind_t WetType>
1082  ATTRIBUTE_PURE
1083  static auto
1084  compare_impl_(const value_t& l, const value_t& r)
1085  -> std::enable_if_t<WetType != wet_kind_t::bitset,
1086  int>
1087  {
1088  return lexicographical_cmp(l, r, monomial_compare);
1089  }
1090 
1091  template <wet_kind_t WetType>
1092  ATTRIBUTE_PURE
1093  static auto
1094  compare_impl_(const value_t& l, const value_t& r)
1095  -> std::enable_if_t<WetType == wet_kind_t::bitset,
1096  int>
1097  {
1098  return l.set() - r.set();
1099  }
1100 
1101  ATTRIBUTE_PURE
1102  static int
1103  compare(const value_t& l, const value_t& r)
1104  {
1105  return compare_impl_<value_t::kind>(l, r);
1106  }
1107 
1108 
1109  /*--------------.
1110  | less(l, r). |
1111  `--------------*/
1112 
1113  ATTRIBUTE_PURE
1114  static bool monomial_less(const monomial_t& lhs, const monomial_t& rhs)
1115  {
1116  if (labelset_t::less(label_of(lhs), label_of(rhs)))
1117  return true;
1118  else if (labelset_t::less(label_of(rhs), label_of(lhs)))
1119  return false;
1120  else
1121  return weightset_t::less(weight_of(lhs), weight_of(rhs));
1122  }
1123 
1124  template <wet_kind_t WetType>
1125  ATTRIBUTE_PURE
1126  static auto
1127  less_impl_(const value_t& l, const value_t& r)
1128  -> std::enable_if_t<WetType != wet_kind_t::bitset,
1129  bool>
1130  {
1131  return boost::range::lexicographical_compare(l, r, monomial_less);
1132  }
1133 
1134  template <wet_kind_t WetType>
1135  ATTRIBUTE_PURE
1136  static auto
1137  less_impl_(const value_t& l, const value_t& r)
1138  -> std::enable_if_t<WetType == wet_kind_t::bitset,
1139  bool>
1140  {
1141  return l.set() < r.set();
1142  }
1143 
1144  ATTRIBUTE_PURE
1145  static bool
1146  less(const value_t& l, const value_t& r)
1147  {
1148  return less_impl_<value_t::kind>(l, r);
1149  }
1150 
1151 
1157  value_t
1158  transpose(const value_t& v) const
1159  {
1160  auto res = value_t{};
1161  auto label_transpose
1162  = static_if<context_t::is_lar>
1163  ([](const auto& ls, const auto& l) { return ls.transposition(l); },
1164  [](const auto& ls, const auto& l) { return ls.transpose(l); });
1165  for (const auto& i: v)
1166  res.set(label_transpose(*labelset(), label_of(i)),
1167  weightset()->transpose(weight_of(i)));
1168  return res;
1169  }
1170 
1171 
1172  /*--------.
1173  | hash. |
1174  `--------*/
1175  ATTRIBUTE_PURE
1176  static size_t hash(const monomial_t& m, size_t res = 0)
1177  {
1178  hash_combine(res, labelset_t::hash(label_of(m)));
1179  hash_combine(res, weightset_t::hash(weight_of(m)));
1180  return res;
1181  }
1182 
1183  template <wet_kind_t WetType>
1184  ATTRIBUTE_PURE
1185  static auto
1187  -> std::enable_if_t<WetType != wet_kind_t::bitset,
1188  size_t>
1189  {
1190  size_t res = 0;
1191  for (const auto& m: p)
1192  res = hash(m, res);
1193  return res;
1194  }
1195 
1196  template <wet_kind_t WetType>
1197  ATTRIBUTE_PURE
1198  static auto
1200  -> std::enable_if_t<WetType == wet_kind_t::bitset,
1201  size_t>
1202  {
1203  return hash_value(p.set());
1204  }
1205 
1206  ATTRIBUTE_PURE
1207  static size_t hash(const value_t& v)
1208  {
1209  return hash_impl_<value_t::kind>(v);
1210  }
1211 
1212 
1214  static self_t make(std::istream& is)
1215  {
1216  // name is, for instance, "polynomialset<lal_char(abcd), z>".
1217  eat(is, "polynomialset<");
1218  auto ctx = Context::make(is);
1219  eat(is, '>');
1220  return {ctx};
1221  }
1222 
1223  std::ostream&
1224  print_set(std::ostream& o, format fmt = {}) const
1225  {
1226  switch (fmt.kind())
1227  {
1228  case format::latex:
1229  o << "\\mathsf{Poly}[";
1230  context().print_set(o, fmt);
1231  o << ']';
1232  break;
1233  case format::sname:
1234  o << "polynomialset<";
1235  context().print_set(o, fmt);
1236  o << '>';
1237  break;
1238  case format::text:
1239  case format::utf8:
1240  o << "Poly[";
1241  context().print_set(o, fmt);
1242  o << ']';
1243  break;
1244  case format::raw:
1245  assert(0);
1246  break;
1247  }
1248  return o;
1249  }
1250 
1256  boost::optional<label_t>
1257  conv_label(std::istream& i, bool weighted, const char sep = '+') const
1258  {
1259  const auto peek = i.peek();
1260  assert(peek != '[');
1261  if (peek == '\\')
1262  {
1263  i.ignore();
1264  if (i.peek() == 'z')
1265  {
1266  i.ignore();
1267  return boost::none;
1268  }
1269  else
1270  i.unget();
1271  }
1272 
1273  // The label is not \z.
1274  // Check if there is a label that comes. Or rather, check if
1275  // there is something else than EOF or the separator, in which
1276  // case it must be a label.
1277  label_t res;
1278  if (peek == EOF || peek == sep || isspace(peek))
1279  {
1280  // There is no label. This counts as '$', the special
1281  // label.
1282  //
1283  // Indeed, that's how we represent the initial and final
1284  // transitions: '$ -> 0 "<2>"'. Using the one label is
1285  // tempting, but it does not exist for lal_char for
1286  // instance. And it would be wrong to have '\e' when we
1287  // can, and '$' otherwise...
1288  //
1289  // However, we must have at least a weight: a completely
1290  // empty mononial ($ -> 0 "<2>,") is invalid.
1291  VCSN_REQUIRE(weighted,
1292  *this, ": conv: invalid monomial: ",
1293  str_escape(peek),
1294  " (did you mean \\e or \\z?)");
1295  res = labelset()->special();
1296  }
1297  else
1298  {
1299  const auto pos = i.tellg();
1300  res = labelset()->conv(i);
1301  // In law_char, when reading the monomial `a|b` (yes, `|` is
1302  // not escaped), we looped for ever: the `a` was read by
1303  // setalpha::get_word, which then returned, and then
1304  // conv_label repeatedly called get_word on `|b`, which
1305  // endlessly returned the empty word, refusing to pass the
1306  // `|`.
1307  //
1308  // Make sure we catch this. Beware that tellg returns -1
1309  // (yes, signed!) on EOF.
1310  require(i.peek() == EOF || pos < i.tellg(),
1311  *this, ": invalid implicit empty word before: ", i);
1312  }
1313  return res;
1314  }
1315 
1317  weight_t
1318  conv_weight(std::istream& i) const
1319  {
1320  if (i.peek() == langle)
1321  // FIXME: convert to use conv(std::istream).
1322  //
1323  // The problem is when we have a rational expression as a
1324  // weight: in that case, conv expect to parse up to EOF, not
1325  // up to '>'. We first need to fix the parsing of expression
1326  // to work on a flow, to be able to use weightset()->conv
1327  // here. Which means to get back the stream from a Flex
1328  // scanner. It might not be easy.
1329  return ::vcsn::conv(*weightset(), bracketed(i, langle, rangle));
1330  else
1331  return weightset()->one();
1332  }
1333 
1340  boost::optional<monomial_t>
1341  conv_monomial(std::istream& i, const char sep = '+') const
1342  {
1343 #define SKIP_SPACES() \
1344  while (isspace(i.peek())) \
1345  i.ignore()
1346 
1347  // Nothing to read: signal EOF as an empty result.
1348  SKIP_SPACES();
1349  if (i.peek() == EOF)
1350  return boost::none;
1351 
1352  // Possibly a weight in braces.
1353  bool weighted = i.peek() == langle;
1354  weight_t w = conv_weight(i);
1355 
1356  // Possibly, a label.
1357  SKIP_SPACES();
1358  auto l = conv_label(i, weighted, sep);
1359  require(l, *this, ": \\z is invalid for monomials");
1360  return monomial_t{*l, w};
1361 #undef SKIP_SPACES
1362  }
1363 
1371  value_t
1372  conv(std::istream& i, const char sep = '+') const
1373  {
1374  auto res = value_t{};
1375 #define SKIP_SPACES() \
1376  while (isspace(i.peek())) \
1377  i.ignore()
1378 
1379  do
1380  {
1381  // Possibly a weight in braces.
1382  SKIP_SPACES();
1383  const bool weighted = i.peek() == langle;
1384  const weight_t w = conv_weight(i);
1385 
1386  SKIP_SPACES();
1387  // Possibly, a label.
1388  // Handle label classes.
1389  if (i.peek() == '[')
1390  labelset()->convs(i, [this, &res, &w](const label_t& l)
1391  {
1392  add_here(res, l, w);
1393  });
1394  else if (auto l = conv_label(i, weighted, sep))
1395  {
1396  require(l, *this, ": \\z is invalid for monomials");
1397  add_here(res, *l, w);
1398  }
1399 
1400  // sep (e.g., '+'), or stop parsing.
1401  SKIP_SPACES();
1402  if (i.peek() == sep)
1403  i.ignore();
1404  else
1405  break;
1406  }
1407  while (true);
1408 #undef SKIP_SPACES
1409 
1410  return res;
1411  }
1412 
1414  std::ostream&
1415  print(const monomial_t& m, std::ostream& out = std::cout,
1416  format fmt = {}) const
1417  {
1418  static bool parens = getenv("VCSN_PARENS");
1419  print_weight_(weight_of(m), out, fmt);
1420  if (parens)
1421  out << (fmt == format::latex ? "\\left(" : "(");
1422  labelset()->print(label_of(m), out, fmt.for_labels());
1423  if (parens)
1424  out << (fmt == format::latex ? "\\right)" : ")");
1425  return out;
1426  }
1427 
1434  std::ostream&
1435  print(const value_t& v, std::ostream& out = std::cout,
1436  format fmt = {},
1437  const std::string& sep = " + ") const
1438  {
1439  if (is_zero(v))
1440  out << (fmt == format::latex ? "\\emptyset"
1441  : fmt == format::utf8 ? "∅"
1442  : "\\z");
1443  else
1444  {
1445  const auto s =
1446  (sep == " + "
1447  ? (fmt == format::latex ? std::string{" \\oplus "}
1448  : fmt == format::utf8 ? std::string{"⊕"}
1449  : sep)
1450  : sep);
1451  print_(v, out, fmt, s);
1452  }
1453  return out;
1454  }
1455 
1456  private:
1458  std::ostream&
1459  print_weight_(const weight_t w, std::ostream& out,
1460  format fmt) const
1461  {
1462  static bool parens = getenv("VCSN_PARENS");
1463  if (parens || weightset()->show_one() || !weightset()->is_one(w))
1464  {
1465  out << (fmt == format::latex ? "\\left\\langle "
1466  : fmt == format::utf8 ? "⟨"
1467  : "<");
1468  weightset()->print(w, out, fmt.for_weights());
1469  out << (fmt == format::latex ? "\\right\\rangle "
1470  : fmt == format::utf8 ? "⟩"
1471  : ">");
1472  }
1473  return out;
1474  }
1475 
1477  std::ostream&
1478  print_without_classes_(const value_t& v, std::ostream& out,
1479  format fmt,
1480  const std::string& sep) const
1481  {
1482  bool first = true;
1483  for (const auto& m: v)
1484  {
1485  if (!first)
1486  out << sep;
1487  first = false;
1488  print(m, out, fmt);
1489  }
1490  return out;
1491  }
1492 
1494  std::ostream&
1495  print_with_classes_(const value_t& v, std::ostream& out,
1496  format fmt,
1497  const std::string& sep) const
1498  {
1499  using std::begin;
1500  using std::end;
1501 
1502  // We can use a vector, as we know that the labels are already
1503  // sorted, and random access iteration will be handy below.
1504  using labels_t = std::vector<label_t>;
1505 
1506  // Cluster the letters per weight.
1507  auto per_weight = std::map<weight_t, labels_t,
1509  // No classes if the weights of the letters aren't all the same.
1510  for (const auto& m: v)
1511  if (!labelset()->is_one(label_of(m)))
1512  per_weight[weight_of(m)].emplace_back(label_of(m));
1513 
1514  // Sort the clusters per label.
1515  auto per_label = std::map<label_t,
1516  std::pair<weight_t, labels_t>,
1518  for (const auto& p: per_weight)
1519  // Split classes which are too small.
1520  if (p.second.size() < 3)
1521  for (auto l: p.second)
1522  per_label[l] = std::make_pair(p.first, labels_t{l});
1523  else
1524  per_label[detail::front(p.second)] = p;
1525 
1526  // Whether we must not issue a separator.
1527  bool first = true;
1528 
1529  // Print with classes. First, the constant-term.
1530  if (labelset()->is_one(label_of(detail::front(v))))
1531  {
1532  print(detail::front(v), out, fmt);
1533  first = false;
1534  }
1535 
1536  for (const auto& p: per_label)
1537  {
1538  if (!first)
1539  out << sep;
1540  first = false;
1541 
1542  // The weight.
1543  print_weight_(p.second.first, out, fmt);
1544 
1545  if (1 < p.second.second.size())
1546  // Print the character class. 'letters' are sorted, since
1547  // polynomials are shortlex-sorted on the labels.
1548  print_label_class(*labelset(), p.second.second,
1549  out, fmt.for_labels());
1550  else
1551  labelset()->print(detail::front(p.second.second),
1552  out, fmt.for_labels());
1553  }
1554  return out;
1555  }
1556 
1558  template <typename Ctx = context_t>
1560  std::ostream&>
1561  print_(const value_t& v, std::ostream& out,
1562  format fmt = {},
1563  const std::string& sep = " + ") const
1564  {
1565  return print_without_classes_(v, out, fmt, sep);
1566  }
1567 
1570  template <typename Ctx = context_t>
1572  std::ostream&>
1573  print_(const value_t& v, std::ostream& out,
1574  format fmt = {},
1575  const std::string& sep = " + ") const
1576  {
1577  // No classes if not at least 3 elements.
1578  if (sep == " + " || v.size() <= 2)
1579  return print_without_classes_(v, out, fmt, sep);
1580  else
1581  return print_with_classes_(v, out, fmt, sep);
1582  }
1583 
1584 
1585  private:
1587 
1589  constexpr static char langle = '<';
1591  constexpr static char rangle = '>';
1592  };
1593 
1594  template <typename Context,
1595  wet_kind_t Kind = detail::wet_kind<labelset_t_of<Context>,
1598  make_polynomialset(const Context& context)
1599  {
1600  return {context};
1601  }
1602 
1603  template <typename Ctx1, wet_kind_t Kind1,
1604  typename Ctx2, wet_kind_t Kind2>
1605  struct join_impl<polynomialset<Ctx1, Kind1>,
1606  polynomialset<Ctx2, Kind2>>
1607  {
1608  // Use the default kind.
1611  const polynomialset<Ctx2, Kind2>& ps2)
1612  {
1613  return {vcsn::join(ps1.context(), ps2.context())};
1614  }
1615  };
1616 
1617  template <typename Ctx1, wet_kind_t Kind1,
1618  typename WS2>
1619  struct join_impl<polynomialset<Ctx1, Kind1>, WS2>
1620  {
1621  using type
1622  = polynomialset<context<typename Ctx1::labelset_t,
1624  static type join(const polynomialset<Ctx1, Kind1>& ps1, const WS2& ws2)
1625  {
1626  return {*ps1.labelset(), vcsn::join(*ps1.weightset(), ws2)};
1627  }
1628  };
1629  }
1630 }
static ATTRIBUTE_PURE auto less_impl_(const value_t &l, const value_t &r) -> std::enable_if_t< WetType==wet_kind_t::bitset, bool >
Aut transpose(const transpose_automaton< Aut > &aut)
The transpose of a transpose automaton is the original automaton.
Definition: transpose.hh:253
std::enable_if_t<!Ctx::is_lar, value_t & > add_ldivide_here(value_t &res, const value_t &l, const value_t &r) const
The left-division of polynomials l and r: res += l \ r.
value_t conv(const WS &ws, const typename WS::value_t &v) const
FIXME: use enable_if to prevent this from being instantiated when WS is a polynomialset.
Print as a parsable type string.
Definition: format.hh:26
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
value_t star(const value_t &v) const
The star of polynomial v.
decltype(join(std::declval< ValueSets >()...)) join_t
The type of the join of the ValueSets.
Definition: join.hh:78
std::enable_if_t<!labelset_t_of< Ctx >::is_letterized(), std::ostream & > print_(const value_t &v, std::ostream &out, format fmt={}, const std::string &sep=" + ") const
Print a non-null value for a non letterized labelset.
typename detail::weightset_t_of_impl< base_t< ValueSet > >::type weightset_t_of
Definition: traits.hh:67
format for_labels() const
A copy of this format, but to print labels.
Definition: format.hh:42
static type join(const polynomialset< Ctx1, Kind1 > &ps1, const WS2 &ws2)
value_t rmul_label(const value_t &v, const label_t &rhs) const
Right product.
int lexicographical_cmp(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Compare comp)
Lexicographical three-way comparison between two ranges.
Definition: algorithm.hh:128
static constexpr bool show_one()
Request the map implementation.
static ATTRIBUTE_PURE auto hash_impl_(const value_t &p) -> std::enable_if_t< WetType !=wet_kind_t::bitset, size_t >
In the general case, normalize by the first (non null) weight.
const labelset_ptr & labelset() const
value_t sub(const value_t &l, const value_t &r) const
The subtraction of polynomials l and r.
#define SKIP_SPACES()
value_t conjunction(const value_t &l, const value_t &r) const
monomial_t determinize(value_t v) const
"Determinize" this polynomial: turn into a monomial.
void clear(value_t &v)
Set to zero.
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:147
value_t rdivide(const value_t &l, const value_t &r) const
value_t lgcd(const value_t &lhs, const value_t &rhs) const
LGCD between two polynomials.
const weight_t get_weight(const value_t &v, const label_t &l) const ATTRIBUTE_PURE
value_t & new_weight(value_t &v, const label_t &l, const weight_t w) const
Set the monomial of l in v to weight w.
std::enable_if_t< labelset_t_of< Ctx >::is_letterized(), std::ostream & > print_(const value_t &v, std::ostream &out, format fmt={}, const std::string &sep=" + ") const
Print a non-null value for a letterized labelset (e.g., letterset or nullableset. ...
static ATTRIBUTE_PURE size_t hash(const value_t &v)
std::ostream & print(const value_t &v, std::ostream &out=std::cout, format fmt={}, const std::string &sep=" + ") const
Print a value (a polynomial).
ValueSet::value_t lgcd(const ValueSet &vs, const typename ValueSet::value_t &lhs, const typename ValueSet::value_t &rhs)
Left-division of values.
Definition: divide.hh:91
value_t conv(const polynomialset< C, K > &sps, const typename polynomialset< C, K >::value_t &v) const
Convert from another polynomialset to type_t.
std::ostream & print_set(std::ostream &o, format fmt={}) const
Definition: context.hh:107
static const monomial_t & monomial_one()
The unit monomial.
constant< type_t::one, Context > one
Definition: fwd.hh:121
polynomialset_impl(const context_t &ctx)
Aut1 & add_here(Aut1 &res, const Aut2 &b, standard_tag)
Merge transitions of b into those of res.
Definition: add.hh:28
std::enable_if_t<!Ctx::is_lar, value_t > conjunction_impl_(const value_t &l, const value_t &r) const
The conjunction of polynomials l and r.
auto mul_impl_(const value_t &l, const value_t &r) const -> std::enable_if_t< WetType==wet_kind_t::bitset, value_t >
The product of polynomials l and r.
wet_kind_t
Different implementations of wets.
Definition: wet.hh:197
polynomialset< Context, Kind > make_polynomialset(const Context &context)
static ATTRIBUTE_PURE bool monomial_equal(const monomial_t &lhs, const monomial_t &rhs)
decltype(std::declval< labelset_t_of< Ctx > >() .rweight(std::declval< label_t_of< Ctx > >(), std::declval< weight_t_of< Ctx > >())) rweight_t
Detect whether the labelset features rweight.
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
static ATTRIBUTE_PURE bool less(const value_t &l, const value_t &r)
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:21
value_t complement(const value_t &v) const
Complement this polynomial.
value_t value(const label_t &l, const weight_t w) const
Create a polynomial with a single value.
value_t ldivide(const monomial_t &l, const value_t &r) const
Left division by a monomial: l \ r.
value_t mul(const value_t &l, const monomial_t &rhs) const
Right product by a monomial.
static constexpr bool has_lightening_weights()
static ATTRIBUTE_PURE auto equal_impl_(const value_t &l, const value_t &r) -> std::enable_if_t< WetType==wet_kind_t::bitset, bool >
auto rdivide(const Aut1 &a1, const Aut2 &a2)
Compute the right quotient.
Definition: conjunction.hh:752
value_t & sub_here(value_t &v, const monomial_t &m) const
v -= m.
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
std::enable_if_t< Ctx::is_lar, value_t & > add_ldivide_here(value_t &res, const value_t &l, const value_t &r) const
The left-division of polynomials l and r: res += l \ r.
value_t lweight(const weight_t w, const value_t &v) const
Left exterior product.
auto tuple(const Auts &... as)
Build the (accessible part of the) tuple.
static self_t make(std::istream &is)
Build from the description in is.
value_t ldivide(const value_t &l, const value_t &r) const
Left division of two polynomials: l \ r.
static bool is_one(const value_t &v) ATTRIBUTE_PURE
Whether is the unit polynomial.
static ATTRIBUTE_PURE auto equal_impl_(const value_t &l, const value_t &r) -> std::enable_if_t< WetType !=wet_kind_t::bitset, bool >
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: functional.hh:72
auto label_is_zero(const LabelSet &ls, const typename LabelSet::value_t &l)
value_t conv(std::istream &i, const char sep='+') const
Read a polynomial from a stream.
auto project() const
The polynomialset for tape Tape.
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
const value_t & zero() const
decltype(std::declval< labelset_t_of< Ctx > >() .compose(std::declval< label_t_of< Ctx > >(), std::declval< label_t_of< Ctx > >())) compose_t
Detect whether the labelset features a binary compose.
bool is_zero(const value_t &v) const
value_t & set_weight(value_t &v, const label_t &l, const weight_t w) const
Set the monomial of l in v to weight w.
static ATTRIBUTE_PURE auto compare_impl_(const value_t &l, const value_t &r) -> std::enable_if_t< WetType !=wet_kind_t::bitset, int >
auto rweight(const value_t &v, const weight_t w) const -> value_t
Right exterior product.
auto mul(const value_t &l, const value_t &r) const -> value_t
The product of polynomials l and r.
value_t & add_here(value_t &v, const label_t &l, const weight_t k) const
v += <k>l.
auto join(const ValueSet &vs) -> ValueSet
The join of a single valueset.
Definition: join.hh:44
labelset_t_of< context_t > labelset_t
auto add_here_impl_(value_t &l, const value_t &r) const -> std::enable_if_t<(WetType==wet_kind_t::bitset &&std::is_same< WS, f2 >::value), value_t &>
v += p, F2 and bitsets.
A structure that implements the computation of join(V1, V2).
Definition: join.hh:18
wet< label_t_of< Context >, weight_t_of< Context >, Kind, vcsn::less< labelset_t_of< Context > >, vcsn::hash< labelset_t_of< Context > >, vcsn::equal_to< labelset_t_of< Context > >> wet_of
The corresponding wet for a LabelSet -> WeightSet context.
Definition: wet.hh:863
auto hash_value(const T &v) -> decltype(std::hash< T >
Following the naming convention of Boost.
Definition: functional.hh:45
typename detail::labelset_t_of_impl< base_t< ValueSet > >::type labelset_t_of
Definition: traits.hh:63
typename value_t::value_type monomial_t
A pair <label, weight>.
value_t mul(const monomial_t &lhs, const value_t &v) const
Left product by a monomial.
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
typename context_t::weightset_ptr weightset_ptr
weightset_t_of< context_t > weightset_t
Request the bitset implementation (bool weights).
value_t add(value_t res, const value_t &r) const
The sum of polynomials l and r.
for(const auto &lm:l) for(const auto &rm return res
std::ostream & print(const std::tuple< Args... > &args, std::ostream &o)
Definition: tuple.hh:420
value_t lmul_label(const label_t &lhs, const value_t &v) const
Left product by a label.
auto conjunction(const Aut &a, const Auts &... as)
Build the (accessible part of the) conjunction.
Definition: conjunction.hh:621
static type join(const polynomialset< Ctx1, Kind1 > &ps1, const polynomialset< Ctx2, Kind2 > &ps2)
star_status_t
Definition: star-status.hh:5
typename detail::label_t_of_impl< base_t< ValueSet > >::type label_t_of
Definition: traits.hh:62
value_t infiltrate(const value_t &l, const value_t &r) const
The infiltration of polynomials l and r.
static ATTRIBUTE_PURE size_t hash(const monomial_t &m, size_t res=0)
auto norm(const value_t &v) const -> weight_t
The norm: the weight with which we should divide a polynomial to normalize it.
std::ostream & print(const monomial_t &m, std::ostream &out=std::cout, format fmt={}) const
Print a monomial.
auto mul_impl_(const value_t &l, const value_t &r) const -> std::enable_if_t< WetType !=wet_kind_t::bitset, value_t >
The product of polynomials l and r.
Container::value_type front(const Container &container)
The first member of this Container.
Definition: algorithm.hh:72
std::enable_if_t< Ctx::is_lar, value_t > conjunction_impl_(const value_t &l, const value_t &r) const
The conjunction of polynomials l and r.
value_t & del_weight(value_t &v, const label_t &l) const
Remove the monomial of l in v.
std::ostream & print_weight_(const weight_t w, std::ostream &out, format fmt) const
Print a weight.
static constexpr bool is_commutative()
void weight_set(welement< Label, Weight > &m, const Weight &w)
Set the weight of a welement.
Definition: wet.hh:162
static symbol sname()
The static name.
static ATTRIBUTE_PURE bool equal(const value_t &l, const value_t &r)
Whether l == r.
auto scalar_product(const value_t &l, const value_t &r) const -> std::enable_if_t<(WetType==wet_kind_t::bitset &&std::is_same< WS, f2 >::value), weight_t >
The sum of the weights of the common labels.
static ATTRIBUTE_PURE auto compare_impl_(const value_t &l, const value_t &r) -> std::enable_if_t< WetType==wet_kind_t::bitset, int >
typename labelset_t::value_t label_t
Polynomials over labels.
std::ostream & print_without_classes_(const value_t &v, std::ostream &out, format fmt, const std::string &sep) const
Print a polynomial value without classes.
auto add_here_impl_(value_t &l, const value_t &r) const -> std::enable_if_t<(WetType==wet_kind_t::bitset &&std::is_same< WS, b >::value), value_t &>
v += p, B and bitsets.
z::value_t operator()(const value_t &v) const
auto factor(const Aut &aut) -> decltype(::vcsn::copy(aut))
Definition: prefix.hh:106
typename context_t::labelset_ptr labelset_ptr
Linear combination of labels: map labels to weights.
Definition: fwd.hh:41
ATTRIBUTE_NORETURN void raise_not_starrable(const WeightSet &ws, const typename WeightSet::value_t &w)
This value is not starrable.
Definition: weightset.hh:235
auto weight_of(const welement< Label, Weight > &m) -> decltype(m.weight())
The weight of a welement.
Definition: wet.hh:154
auto mul(const value_t &p, const label_t &l, const weight_t w) const -> value_t
The product of polynomials l and r.
static const value_t & one()
The unit polynomial.
auto scalar_product(const value_t &l, const value_t &r) const -> std::enable_if_t<(WetType==wet_kind_t::bitset &&std::is_same< WS, b >::value), weight_t >
The sum of the weights of the common labels.
static ATTRIBUTE_PURE int monomial_compare(const monomial_t &lhs, const monomial_t &rhs)
WeightSet::value_t operator()(const value_t &v) const
std::ostream & print_with_classes_(const value_t &v, std::ostream &out, format fmt, const std::string &sep) const
Print a polynomial value with classes.
auto project(const value_t &v) const
Extract a single tape.
value_t & ldivide_here(const weight_t w, value_t &v) const
Left exterior division.
auto add_here_impl_(value_t &l, const value_t &r) const -> std::enable_if_t< WetType !=wet_kind_t::bitset, value_t &>
v += p, default case.
auto tuple(Polys &&... vs) const -> value_t
Build a tuple of polynomials: (e.E+f.F)|(g.G+h.H) => eg.
auto label_of(const welement< Label, Weight > &m) -> decltype(m.label())
The label of a welement.
Definition: wet.hh:146
symbol sname()
Definition: name.hh:65
label_t to_label(const value_t &v) const
Convert into a label.
boost::optional< monomial_t > conv_monomial(std::istream &i, const char sep='+') const
Read a monomial from a stream.
Print for LaTeX.
Definition: format.hh:22
auto compose(const value_t &l, const value_t &r) const -> std::enable_if_t< has_compose_fn< Ctx >
The composition of polynomials l and r when the context features compose.
std::ostream & print_set(std::ostream &o, format fmt={}) const
static ATTRIBUTE_PURE auto hash_impl_(const value_t &p) -> std::enable_if_t< WetType==wet_kind_t::bitset, size_t >
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
std::string bracketed(std::istream &i, char lbracket, char rbracket)
Extract the string which is here between lbracket and rbracket.
Definition: stream.cc:17
void hash_combine(std::size_t &seed, const T &v)
Definition: functional.hh:63
Functor to compare Values of ValueSets.
Definition: functional.hh:91
value_t normalize(value_t res) const
Normalized v.
value_t & add_here(value_t &l, const value_t &r) const
value_t & rdivide_here(value_t &v, const weight_t w) const
Right exterior division.
static ATTRIBUTE_PURE int compare(const value_t &l, const value_t &r)
value_t transpose(const value_t &v) const
Transpose the labels and the weights.
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:87
value_t abs(const value_t &v) const
Map all weights to their absolute value.
monomial_t ldivide(const monomial_t &l, const monomial_t &r) const
Left division between two mononials: l \ r.
const weightset_ptr & weightset() const
weight_t conv_weight(std::istream &i) const
Read a weight, if there is one, bracketed.
typename detail::weight_t_of_impl< base_t< ValueSet > >::type weight_t_of
Definition: traits.hh:66
std::string to_string(direction d)
Conversion to string.
Definition: direction.cc:7
monomial_t mul(const monomial_t &l, const monomial_t &r) const
The product of monomials l and r.
void print_(std::ostream &o, const T &arg, long)
Serialize arg into o.
Definition: raise.hh:26
std::enable_if_t<!is_letterized_t< labelset_t_of< Aut > >{}, bool > is_letterized(const Aut &aut)
Definition: letterize.hh:161
value_t & add_here(value_t &v, const monomial_t &m) const
v += m.
auto compose(const polynomialset< Ctx1 > &ps1, const typename polynomialset< Ctx1 >::value_t &p1, const polynomialset< Ctx2 > &ps2, const typename polynomialset< Ctx2 >::value_t &p2) const -> std::enable_if_t< are_composable< Ctx1, Ctx2 >
The composition of polynomials l and r when the context is a composable tupleset. ...
static ATTRIBUTE_PURE auto less_impl_(const value_t &l, const value_t &r) -> std::enable_if_t< WetType !=wet_kind_t::bitset, bool >
decltype(std::declval< LabelSet >().zero()) zero_mem_fn_t
The type of the LabelSet::zero() member function.
ExpansionSet::value_t normalize(const ExpansionSet &xs, typename ExpansionSet::value_t x)
Normalize an expansion.
#define VCSN_REQUIRE(Cond,...)
A macro similar to require.
Definition: raise.hh:98
weight_t_of< context_t > weight_t
weight_t normalize_here(value_t &v) const
Normalize v in place: compute the LGCD of the weights, ldivide the monomials with that factor...
for(const auto &m1:p1) for(const auto &m2 return res
int compare(const Lhs &lhs, const Rhs &rhs)
Comparison between lhs and rhs.
void cross(Fun f)
Variadic Cartesian product of containers.
Definition: tuple.hh:319
wet_of< context_t, Kind > value_t
return res
Definition: multiply.hh:399
static constexpr star_status_t star_status()
static ATTRIBUTE_PURE bool monomial_less(const monomial_t &lhs, const monomial_t &rhs)
auto scalar_product(const value_t &l, const value_t &r) const -> std::enable_if_t< WetType !=wet_kind_t::bitset, weight_t >
The sum of the weights of the common labels.
const context_t & context() const
static value_t conv(self_t, const value_t &v)
Conversion from (this and) other weightsets.
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:86