Vcsn  2.3
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  // http://llvm.org/bugs/show_bug.cgi?id=18571
34 #if defined __clang__
35 # pragma clang diagnostic push
36 # pragma clang diagnostic ignored "-Wunused-value"
37 #endif
38  template <typename LabelSet>
39  auto label_is_zero(const LabelSet& ls, const typename LabelSet::value_t* l)
40  -> decltype(ls.is_zero(l), bool())
41  {
42  return ls.is_zero(*l);
43  }
44 
45 #if defined __clang__
46 # pragma clang diagnostic pop
47 #endif
48 
49  template <typename LabelSet>
50  bool label_is_zero(const LabelSet&, ...)
51  ATTRIBUTE_CONST;
52 
53  template <typename LabelSet>
54  bool label_is_zero(const LabelSet&, ...)
55  {
56  return false;
57  }
58 
59  namespace detail
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&
135  del_weight(value_t& v, const label_t& l) const
136  {
137  v.erase(l);
138  return v;
139  }
140 
143  value_t&
144  new_weight(value_t& v, const label_t& l, const weight_t w) const
145  {
146  assert(!weightset()->is_zero(w));
147  v.set(l, w);
148  return v;
149  }
150 
152  value_t&
153  set_weight(value_t& v, const label_t& l, const weight_t w) const
154  {
155  if (weightset()->is_zero(w))
156  return del_weight(v, l);
157  else
158  return new_weight(v, l, w);
159  }
160 
161  const weight_t
162  get_weight(const value_t& v, const label_t& l) const ATTRIBUTE_PURE
163  {
164  auto i = v.find(l);
165  if (i == v.end())
166  return weightset()->zero();
167  else
168  return weight_of(*i);
169  }
170 
171 
172  /*---------.
173  | clear. |
174  `---------*/
175 
177  void clear(value_t& v)
178  {
179  v.clear();
180  }
181 
182 
183  /*-------.
184  | add. |
185  `-------*/
186 
188  value_t&
189  add_here(value_t& v, const label_t& l, const weight_t k) const
190  {
191  if (!label_is_zero(*labelset(), &l))
192  {
193  auto i = v.find(l);
194  if (i == v.end())
195  {
196  set_weight(v, l, k);
197  }
198  else
199  {
200  // Do not use set_weight() because it would lookup l
201  // again and we already have the right iterator.
202  auto w2 = weightset()->add(weight_of(*i), k);
203  if (weightset()->is_zero(w2))
204  v.erase(i);
205  else
206  v.set(i, w2);
207  }
208  }
209  return v;
210  }
211 
213  value_t&
214  add_here(value_t& v, const monomial_t& m) const
215  {
216  return add_here(v, label_of(m), weight_of(m));
217  }
218 
220  template <wet_kind_t WetType, typename WS>
221  auto
222  add_here_impl(value_t& l, const value_t& r) const
223  -> std::enable_if_t<WetType != wet_kind_t::bitset,
224  value_t&>
225  {
226  for (const auto& m: r)
227  add_here(l, m);
228  return l;
229  }
230 
232  template <wet_kind_t WetType, typename WS>
233  auto
234  add_here_impl(value_t& l, const value_t& r) const
235  -> std::enable_if_t<(WetType == wet_kind_t::bitset
236  && std::is_same<WS, b>::value),
237  value_t&>
238  {
239  l.set() |= r.set();
240  return l;
241  }
242 
244  template <wet_kind_t WetType, typename WS>
245  auto
246  add_here_impl(value_t& l, const value_t& r) const
247  -> std::enable_if_t<(WetType == wet_kind_t::bitset
248  && std::is_same<WS, f2>::value),
249  value_t&>
250  {
251  l.set() ^= r.set();
252  return l;
253  }
254 
255  value_t&
256  add_here(value_t& l, const value_t& r) const
257  {
258  return add_here_impl<value_t::kind, weightset_t>(l, r);
259  }
260 
262  value_t add(const value_t& l, const value_t& r) const
263  {
264  value_t res = l;
265  add_here(res, r);
266  return res;
267  }
268 
269 
270  /*-------.
271  | sub. |
272  `-------*/
273 
275  value_t&
276  sub_here(value_t& v, const monomial_t& m) const
277  {
278  if (!label_is_zero(*labelset(), &label_of(m)))
279  {
280  auto i = v.find(label_of(m));
281  if (i == v.end())
282  {
283  raise(*this, ": sub_here: invalid arguments: ",
284  to_string(*this, v), ", ", to_string(*this, m));
285  }
286  else
287  {
288  // Do not use set_weight() because it would lookup w
289  // again and we already have the right iterator.
290  auto w2 = weightset()->sub(weight_of(*i), weight_of(m));
291  if (weightset()->is_zero(w2))
292  v.erase(i);
293  else
294  weight_set(*i, w2);
295  }
296  }
297  return v;
298  }
299 
301  value_t
302  sub(const value_t& l, const value_t& r) const
303  {
304  value_t res = l;
305  for (const auto& rm: r)
306  sub_here(res, rm);
307  return res;
308  }
309 
310 
311  /*-------.
312  | mul. |
313  `-------*/
314 
316  monomial_t
317  mul(const monomial_t& l, const monomial_t& r) const
318  {
319  return {labelset()->mul(label_of(l), label_of(r)),
320  weightset()->mul(weight_of(l), weight_of(r))};
321  }
322 
325  template <wet_kind_t WetType>
326  auto
327  mul_impl(const value_t& l, const value_t& r) const
328  -> std::enable_if_t<WetType != wet_kind_t::bitset,
329  value_t>
330  {
331  value_t res;
332  for (const auto& lm: l)
333  for (const auto& rm: r)
334  add_here(res,
335  labelset()->mul(label_of(lm), label_of(rm)),
336  weightset()->mul(weight_of(lm), weight_of(rm)));
337  return res;
338  }
339 
342  template <wet_kind_t WetType>
343  auto
344  mul_impl(const value_t& l, const value_t& r) const
345  -> std::enable_if_t<WetType == wet_kind_t::bitset,
346  value_t>
347  {
348  return l.set() & r.set();
349  }
350 
352  auto
353  mul(const value_t& l, const value_t& r) const
354  -> value_t
355  {
356  return mul_impl<value_t::kind>(l, r);
357  }
358 
360  auto
361  mul(const value_t& p, const label_t& l, const weight_t w) const
362  -> value_t
363  {
364  value_t res;
365  for (const auto& m: p)
366  add_here(res,
367  labelset()->mul(label_of(m), l),
368  weightset()->mul(weight_of(m), w));
369  return res;
370  }
371 
372 
373  /*---------------.
374  | conjunction. |
375  `---------------*/
376 
379  template <typename Ctx>
380  std::enable_if_t<Ctx::is_lar, value_t>
381  conjunction_impl(const value_t& l, const value_t& r) const
382  {
383  value_t res;
384  for (const auto& lm: l)
385  for (const auto& rm: r)
386  add_here(res,
387  labelset()->conjunction(label_of(lm), label_of(rm)),
388  weightset()->mul(weight_of(lm), weight_of(rm)));
389  return res;
390  }
391 
394  template <typename Ctx>
395  std::enable_if_t<!Ctx::is_lar, value_t>
396  conjunction_impl(const value_t& l, const value_t& r) const
397  {
398  value_t res;
399  for (const auto& p: zip_maps<vcsn::as_tuple>(l, r))
400  add_here(res,
401  label_of(std::get<0>(p)),
402  weightset()->mul(weight_of(std::get<0>(p)),
403  weight_of(std::get<1>(p))));
404  return res;
405  }
406 
407  value_t
408  conjunction(const value_t& l, const value_t& r) const
409  {
410  return conjunction_impl<context_t>(l, r);
411  }
412 
415  value_t
416  infiltrate(const value_t& l, const value_t& r) const
417  {
418  value_t res;
419  for (const auto& lm: l)
420  for (const auto& rm: r)
421  add_here(res,
422  labelset()->infiltrate(label_of(lm), label_of(rm)),
423  weightset()->mul(weight_of(lm), weight_of(rm)));
424  return res;
425  }
426 
429  template <wet_kind_t WetType = value_t::kind>
430  auto
431  scalar_product(const value_t& l, const value_t& r) const
432  -> std::enable_if_t<WetType != wet_kind_t::bitset,
433  weight_t>
434  {
435  auto res = weightset()->zero();
436  for (const auto& p: zip_maps<vcsn::as_tuple>(l, r))
437  res = weightset()->add(res,
438  weightset()->mul(weight_of(std::get<0>(p)),
439  weight_of(std::get<1>(p))));
440  return res;
441  }
442 
445  template <wet_kind_t WetType = value_t::kind, typename WS = weightset_t>
446  auto
447  scalar_product(const value_t& l, const value_t& r) const
448  -> std::enable_if_t<(WetType == wet_kind_t::bitset
449  && std::is_same<WS, b>::value),
450  weight_t>
451  {
452  return l.set().intersects(r.set());
453  }
454 
457  template <wet_kind_t WetType = value_t::kind, typename WS = weightset_t>
458  auto
459  scalar_product(const value_t& l, const value_t& r) const
460  -> std::enable_if_t<(WetType == wet_kind_t::bitset
461  && std::is_same<WS, f2>::value),
462  weight_t>
463  {
464  return (l.set() & r.set()).count() % 2;
465  }
466 
468  value_t abs(const value_t& v) const
469  {
470  value_t res;
471  for (const auto& m: v)
472  add_here(res, label_of(m), weightset()->abs(weight_of(m)));
473  return res;
474  }
475 
477  value_t
478  star(const value_t& v) const
479  {
480  // The only starrable polynomials are scalars (if they are
481  // starrable too).
482  auto s = v.size();
483  if (s == 0)
484  return one();
485  else if (s == 1)
486  {
487  auto i = v.find(labelset()->one());
488  if (i != v.end())
489  return {{i->first, weightset()->star(i->second)}};
490  }
491  raise_not_starrable(*this, v);
492  }
493 
495  value_t
496  lweight(const weight_t w, const value_t& v) const
497  {
498  value_t res;
499  if (weightset()->is_one(w))
500  res = v;
501  else if (!weightset()->is_zero(w))
502  for (const auto& m: v)
503  add_here(res, label_of(m), weightset()->mul(w, weight_of(m)));
504  return res;
505  }
506 
508  value_t
509  lmul_label(const label_t& lhs, const value_t& v) const
510  {
511  value_t res;
512  for (const auto& m: v)
513  add_here(res,
514  labelset()->mul(lhs, label_of(m)),
515  weight_of(m));
516  return res;
517  }
518 
520  value_t
521  mul(const monomial_t& lhs, const value_t& v) const
522  {
523  value_t res;
524  for (const auto& m: v)
525  add_here(res,
526  labelset()->mul(label_of(lhs), label_of(m)),
527  weightset()->mul(weight_of(lhs), weight_of(m)));
528  return res;
529  }
530 
532  template <typename Ctx>
533  using rweight_t
534  = decltype(std::declval<labelset_t_of<Ctx>>()
535  .rweight(std::declval<label_t_of<Ctx>>(),
536  std::declval<weight_t_of<Ctx>>()));
537 
539  template <typename Ctx>
541 
543  auto
544  rweight(const value_t& v, const weight_t w) const
545  -> value_t
546  {
547  value_t res;
548  if (weightset()->is_one(w))
549  res = v;
550  else if (!weightset()->is_zero(w))
551  for (const auto& m: v)
552  // Beware that if the labelset supports weights (e.g.,
553  // polynomial of expressions), we do not multiply the weight
554  // here, but the label.
555  static_if<has_rweight_fn<context_t>{}>
556  ([this, &res] (const auto& ls, const auto& m, const auto& w)
557  {
558  add_here(res,
559  ls.rweight(label_of(m), w),
560  weight_of(m));
561  },
562  [this, &res] (const auto&, const auto& m, const auto& w)
563  {
564  add_here(res,
565  label_of(m),
566  weightset()->mul(w, weight_of(m)));
567  })
568  (*labelset(), m, w);
569  return res;
570  }
571 
573  value_t
574  rmul_label(const value_t& v, const label_t& rhs) const
575  {
576  value_t res;
577  for (const auto& lhs: v)
578  add_here(res,
579  labelset()->mul(label_of(lhs), rhs),
580  weight_of(lhs));
581  return res;
582  }
583 
585  value_t
586  mul(const value_t& l, const monomial_t& rhs) const
587  {
588  value_t res;
589  for (const auto& lhs: l)
590  add_here(res,
591  labelset()->mul(label_of(lhs), label_of(rhs)),
592  weightset()->mul(weight_of(lhs), weight_of(rhs)));
593  return res;
594  }
595 
596  value_t
597  rdivide(const value_t& l, const value_t& r) const
598  {
599  raise(*this, ": rdivide: not implemented (",
600  to_string(*this, l), ", ", to_string(*this, r), ")");
601  }
602 
603  monomial_t
604  ldivide(const monomial_t& l, const monomial_t& r) const
605  {
606  return {labelset()->ldivide(label_of(l), label_of(r)),
607  weightset()->ldivide(weight_of(l), weight_of(r))};
608  }
609 
611  value_t
612  ldivide(const monomial_t& l, const value_t& r) const
613  {
614  value_t res;
615  for (const auto& m: r)
616  add_here(res, ldivide(l, m));
617  return res;
618  }
619 
620  value_t
621  ldivide(const value_t& l, const value_t& r) const
622  {
623  value_t res;
624  if (is_zero(l))
625  raise(*this, ": ldivide: division by zero");
626  else
627  {
628  value_t remainder = r;
629 #if DEBUG
630  std::cerr << "ldivide(";
631  print(l, std::cerr) << ", ";
632  print(r, std::cerr) << "\n";
633 #endif
634  while (!is_zero(remainder))
635  {
636  auto factor = ldivide(detail::front(l), detail::front(remainder));
637 #if DEBUG
638  std::cerr << "factor = "; print(factor, std::cerr) << "\n";
639 #endif
640  add_here(res, factor);
641 #if DEBUG
642  std::cerr << "res = "; print(res, std::cerr) << "\n";
643  std::cerr << "sub = "; print(mul(l, factor), std::cerr) << "\n";
644 #endif
645  remainder = sub(remainder, mul(l, factor));
646 #if DEBUG
647  std::cerr << "rem = "; print(remainder, std::cerr) << "\n";
648 #endif
649  }
650 #if DEBUG
651  std::cerr << "ldivide(";
652  print(l, std::cerr) << ", ";
653  print(r, std::cerr) << ") = ";
654  print(res, std::cerr) << " rem: ";
655  print(remainder, std::cerr) << "\n";
656 #endif
657  if (!is_zero(remainder))
658  raise(*this, ": ldivide: not implemented (",
659  to_string(*this, l), ", ", to_string(*this, r), ")");
660  }
661  return res;
662  }
663 
665  value_t&
666  ldivide_here(const weight_t w, value_t& v) const
667  {
668  if (!weightset()->is_one(w))
669  for (auto&& m: v)
670  weight_set(m, weightset()->ldivide(w, weight_of(m)));
671  return v;
672  }
673 
675  value_t&
676  rdivide_here(value_t& v, const weight_t w) const
677  {
678  if (!weightset()->is_one(w))
679  for (auto& m: v)
680  weight_set(m, weightset()->rdivide(weight_of(m), w));
681  return v;
682  }
683 
690  value_t lgcd(const value_t& lhs, const value_t& rhs) const
691  {
692  using std::begin;
693  using std::end;
694  value_t res;
695  // For each monomial, look for the matching GCD of the weight.
696  auto i = begin(lhs), i_end = end(lhs);
697  auto j = begin(rhs), j_end = end(rhs);
698  for (;
699  i != i_end && j != j_end
700  && labelset()->equal(i->first, j->first);
701  ++i, ++j)
702  res.set(i->first, weightset()->lgcd(i->second, j->second));
703  // If the sets of labels are different, the polynomials
704  // cannot be "colinear", and the GCD is just 1.
705  if (i != i_end || j != j_end)
706  res = one();
707  return res;
708  }
709 
710  /*--------.
711  | norm. |
712  `--------*/
713 
715  template <typename WeightSet, typename Dummy = void>
716  struct norm_
717  {
718  typename WeightSet::value_t operator()(const value_t& v) const
719  {
720  return weight_of(front(v));
721  }
722  const WeightSet& ws_;
723  };
724 
726  template <typename Dummy>
727  struct norm_<z, Dummy>
728  {
729  typename z::value_t operator()(const value_t& v) const
730  {
731  int sign = 0 < weight_of(detail::front(v)) ? 1 : -1;
732  auto res = std::abs(weight_of(detail::front(v)));
733  for (const auto& m: v)
734  res = z_.lgcd(res, std::abs(weight_of(m)));
735  res *= sign;
736  return res;
737  }
738  const z& z_;
739  };
740 
742  template <typename Ctx, wet_kind_t Knd, typename Dummy>
743  struct norm_<polynomialset<Ctx, Knd>, Dummy>
744  {
746 
747  typename ps_t::value_t operator()(const value_t& v) const
748  {
749  typename ps_t::value_t res = weight_of(detail::front(v));
750  for (const auto& p: v)
751  res = ps_.lgcd(res, weight_of(p));
752  return res;
753  }
754  const ps_t& ps_;
755  };
756 
759  auto norm(const value_t& v) const
760  -> weight_t
761  {
762  if (is_zero(v))
763  return weightset()->zero();
764  else
765  return norm_<weightset_t>{*weightset()}(v);
766  }
767 
768 
769  /*-------------.
770  | normalize. |
771  `-------------*/
772 
776  {
777  // Zero is in normal form, don't try to divide by zero.
778  auto res = norm(v);
779  if (!weightset()->is_zero(res))
780  ldivide_here(res, v);
781  return res;
782  }
783 
786  {
787  normalize_here(res);
788  return res;
789  }
790 
791 
792 
793  /*---------------.
794  | tuple(v...). |
795  `---------------*/
796 
799  template <typename... Polys>
800  auto
801  tuple(Polys&&... vs) const
802  -> value_t
803  {
804  auto res = value_t{};
805  detail::cross([&res, this](auto... ms)
806  {
807  this->add_here(res,
808  this->labelset()->tuple(ms.first...),
809  this->weightset()->mul(ms.second...));
810  },
811  std::forward<Polys>(vs)...);
812  return res;
813  }
814 
816  template <size_t Tape>
817  auto project() const
818  {
819  return make_polynomialset(vcsn::detail::project<Tape>(context()));
820  }
821 
823  template <size_t Tape>
824  auto project(const value_t& v) const
825  {
826  auto ps = project<Tape>();
827  auto res = ps.zero();
828  for (const auto& m: v)
829  ps.add_here(res,
830  labelset()->template project<Tape>(label_of(m)),
831  weight_of(m));
832  return res;
833  }
834 
835  /*-----------.
836  | compose. |
837  `-----------*/
838 
840  template <typename Ctx>
841  using compose_t
842  = decltype(std::declval<labelset_t_of<Ctx>>()
843  .compose(std::declval<label_t_of<Ctx>>(),
844  std::declval<label_t_of<Ctx>>()));
845 
847  template <typename Ctx>
849 
850 
853  template <typename Ctx = context_t>
854  auto
855  compose(const value_t& l, const value_t& r) const
856  -> std::enable_if_t<are_composable<Ctx, Ctx>{}, value_t>
857  {
858  value_t res;
859  for (const auto& lm: l)
860  for (const auto& rm: r)
861  if (labelset()->template set<0>().equal(std::get<1>(label_of(lm)),
862  std::get<0>(label_of(rm))))
863  add_here(res, labelset()->tuple(std::get<0>(label_of(lm)),
864  std::get<1>(label_of(rm))),
865  weightset()->mul(weight_of(lm), weight_of(rm)));
866  return res;
867  }
868 
871  template <typename Ctx = context_t>
872  auto
873  compose(const value_t& l, const value_t& r) const
874  -> std::enable_if_t<has_compose_fn<Ctx>{}, value_t>
875  {
876  value_t res;
877  for (const auto& lm: l)
878  for (const auto& rm: r)
879  add_here(res, labelset()->compose(label_of(lm), label_of(rm)),
880  weightset()->mul(weight_of(lm),
881  weight_of(rm)));
882  return res;
883  }
884 
885 
886 
893  label_t to_label(const value_t& v) const
894  {
895  label_t res = labelset()->zero();
896  for (const auto& m: v)
897  res = labelset()->add(res,
898  labelset()->lweight(weight_of(m), label_of(m)));
899  return res;
900  }
901 
906  {
907  weight_t w = normalize_here(v);
908  return {to_label(v), w};
909  }
910 
914  value_t complement(const value_t& v) const
915  {
916  return {{labelset()->complement(to_label(normalize(v))),
917  weightset()->one()}};
918  }
919 
920  /*---------------.
921  | equal(l, r). |
922  `---------------*/
923 
924  ATTRIBUTE_PURE
925  static bool monomial_equal(const monomial_t& lhs,
926  const monomial_t& rhs)
927  {
928  return (labelset_t::equal(label_of(lhs), label_of(rhs))
929  && weightset_t::equal(weight_of(lhs), weight_of(rhs)));
930  }
931 
932  template <wet_kind_t WetType>
933  ATTRIBUTE_PURE
934  static auto
935  equal_impl(const value_t& l, const value_t& r)
936  -> std::enable_if_t<WetType != wet_kind_t::bitset,
937  bool>
938  {
939  return boost::equal(l, r, monomial_equal);
940  }
941 
942  template <wet_kind_t WetType>
943  ATTRIBUTE_PURE
944  static auto
945  equal_impl(const value_t& l, const value_t& r)
946  -> std::enable_if_t<WetType == wet_kind_t::bitset,
947  bool>
948  {
949  return l.set() == r.set();
950  }
951 
952  ATTRIBUTE_PURE
953  static bool
954  equal(const value_t& l, const value_t& r)
955  {
956  return equal_impl<value_t::kind>(l, r);
957  }
958 
960  static const value_t& one()
961  {
962  static value_t res{monomial_one()};
963  return res;
964  }
965 
967  static const monomial_t& monomial_one()
968  {
970  return res;
971  }
972 
974  static bool is_one(const value_t& v) ATTRIBUTE_PURE
975  {
976  if (v.size() != 1)
977  return false;
978  auto i = v.find(labelset_t::one());
979  if (i == v.end())
980  return false;
981  return weightset_t::is_one(i->second);
982  }
983 
984  const value_t&
985  zero() const
986  {
987  static value_t res;
988  return res;
989  }
990 
991  bool
992  is_zero(const value_t& v) const
993  {
994  return v.empty();
995  }
996 
997  static constexpr bool show_one() { return false; }
998  static constexpr star_status_t star_status()
999  {
1000  return weightset_t::star_status();
1001  }
1002 
1004  static value_t
1006  {
1007  return v;
1008  }
1009 
1013  template <typename WS>
1014  value_t
1015  conv(const WS& ws, const typename WS::value_t& v) const
1016  {
1017  return {{labelset()->one(), weightset()->conv(ws, v)}};
1018  }
1019 
1021  template <typename C, wet_kind_t K>
1022  value_t
1024  const typename polynomialset<C, K>::value_t& v) const
1025  {
1026  const typename C::labelset_t& sls = *sps.labelset();
1027  const typename C::weightset_t& sws = *sps.weightset();
1028  const labelset_t& tls = *labelset();
1029  const weightset_t& tws = *weightset();
1030  value_t res;
1031  for (const auto& m: v)
1032  add_here(res, tls.conv(sls, label_of(m)), tws.conv(sws, weight_of(m)));
1033  return res;
1034  }
1035 
1036 
1037  /*--------------.
1038  | less(l, r). |
1039  `--------------*/
1040 
1041  ATTRIBUTE_PURE
1042  static bool monomial_less(const monomial_t& lhs, const monomial_t& rhs)
1043  {
1044  if (labelset_t::less(label_of(lhs), label_of(rhs)))
1045  return true;
1046  else if (labelset_t::less(label_of(rhs), label_of(lhs)))
1047  return false;
1048  else
1049  return weightset_t::less(weight_of(lhs), weight_of(rhs));
1050  }
1051 
1052  template <wet_kind_t WetType>
1053  ATTRIBUTE_PURE
1054  static auto
1055  less_impl(const value_t& l, const value_t& r)
1056  -> std::enable_if_t<WetType != wet_kind_t::bitset,
1057  bool>
1058  {
1059  return boost::range::lexicographical_compare(l, r, monomial_less);
1060  }
1061 
1062  template <wet_kind_t WetType>
1063  ATTRIBUTE_PURE
1064  static auto
1065  less_impl(const value_t& l, const value_t& r)
1066  -> std::enable_if_t<WetType == wet_kind_t::bitset,
1067  bool>
1068  {
1069  return l.set() < r.set();
1070  }
1071 
1072  ATTRIBUTE_PURE
1073  static bool
1074  less(const value_t& l, const value_t& r)
1075  {
1076  return less_impl<value_t::kind>(l, r);
1077  }
1078 
1079 
1080  value_t
1081  transpose(const value_t& v) const
1082  {
1083  value_t res;
1084  for (const auto& i: v)
1085  res.set(labelset()->transpose(label_of(i)),
1086  weightset()->transpose(weight_of(i)));
1087  return res;
1088  }
1089 
1090 
1091  /*--------.
1092  | hash. |
1093  `--------*/
1094  ATTRIBUTE_PURE
1095  static size_t hash(const monomial_t& m, size_t res = 0)
1096  {
1097  hash_combine(res, labelset_t::hash(label_of(m)));
1098  hash_combine(res, weightset_t::hash(weight_of(m)));
1099  return res;
1100  }
1101 
1102  template <wet_kind_t WetType>
1103  ATTRIBUTE_PURE
1104  static auto
1105  hash_impl(const value_t& p)
1106  -> std::enable_if_t<WetType != wet_kind_t::bitset,
1107  size_t>
1108  {
1109  size_t res = 0;
1110  for (const auto& m: p)
1111  res = hash(m, res);
1112  return res;
1113  }
1114 
1115  template <wet_kind_t WetType>
1116  ATTRIBUTE_PURE
1117  static auto
1118  hash_impl(const value_t& p)
1119  -> std::enable_if_t<WetType == wet_kind_t::bitset,
1120  size_t>
1121  {
1122  return hash_value(p.set());
1123  }
1124 
1125  ATTRIBUTE_PURE
1126  static size_t hash(const value_t& v)
1127  {
1128  return hash_impl<value_t::kind>(v);
1129  }
1130 
1131 
1133  static self_t make(std::istream& is)
1134  {
1135  // name is, for instance, "polynomialset<lal_char(abcd), z>".
1136  eat(is, "polynomialset<");
1137  auto ctx = Context::make(is);
1138  eat(is, '>');
1139  return {ctx};
1140  }
1141 
1142  std::ostream&
1143  print_set(std::ostream& o, format fmt = {}) const
1144  {
1145  switch (fmt.kind())
1146  {
1147  case format::latex:
1148  o << "\\mathsf{Poly}[";
1149  context().print_set(o, fmt);
1150  o << ']';
1151  break;
1152  case format::sname:
1153  o << "polynomialset<";
1154  context().print_set(o, fmt);
1155  o << '>';
1156  break;
1157  case format::text:
1158  case format::utf8:
1159  o << "Poly[";
1160  context().print_set(o, fmt);
1161  o << ']';
1162  break;
1163  case format::raw:
1164  assert(0);
1165  break;
1166  }
1167  return o;
1168  }
1169 
1175  boost::optional<label_t>
1176  conv_label(std::istream& i, bool weighted, const char sep = '+') const
1177  {
1178  int peek = i.peek();
1179  assert(peek != '[');
1180  if (peek == '\\')
1181  {
1182  i.ignore();
1183  if (i.peek() == 'z')
1184  {
1185  i.ignore();
1186  return boost::none;
1187  }
1188  else
1189  i.unget();
1190  }
1191 
1192  // The label is not \z.
1193  // Check if there is a label that comes. Or rather, check if
1194  // there is something else than EOF or the separator, in which
1195  // case it must be a label.
1196  label_t res;
1197  if (peek == EOF || peek == sep || isspace(peek))
1198  {
1199  // There is no label. This counts as '$', the special
1200  // label.
1201  //
1202  // Indeed, that's how we represent the initial and final
1203  // transitions: '$ -> 0 "<2>"'. Using the one label is
1204  // tempting, but it does not exist for lal_char for
1205  // instance. And it would be wrong to have '\e' when we
1206  // can, and '$' otherwise...
1207  //
1208  // However, we must have at least a weight: a completely
1209  // empty mononial ($ -> 0 "<2>,") is invalid.
1210  VCSN_REQUIRE(weighted,
1211  *this, ": conv: invalid monomial: ",
1212  str_escape(peek),
1213  " (did you mean \\e or \\z?)");
1214  res = labelset()->special();
1215  }
1216  else
1217  {
1218  auto pos = i.tellg();
1219  res = labelset()->conv(i);
1220  // In law_char, when reading the monomial `a|b` (yes, `|` is
1221  // not escaped), we looped for ever: the `a` was read by
1222  // setalpha::get_word, which then returned, and then
1223  // conv_label repeatedly called get_word on `|b`, which
1224  // endlessly returned the empty word, refusing to pass the
1225  // `|`.
1226  //
1227  // Make sure we catch this. Beware that tellg returns -1
1228  // (yes, signed!) on EOF.
1229  require(i.peek() == EOF || pos < i.tellg(),
1230  *this, ": invalid implicit empty word before: ", i);
1231  }
1232  return res;
1233  }
1234 
1236  weight_t
1237  conv_weight(std::istream& i) const
1238  {
1239  if (i.peek() == langle)
1240  // FIXME: convert to use conv(std::istream).
1241  //
1242  // The problem is when we have a rational expression as a
1243  // weight: in that case, conv expect to parse up to EOF, not
1244  // up to '>'. We first need to fix the parsing of expression
1245  // to work on a flow, to be able to use weightset()->conv
1246  // here. Which means to get back the stream from a Flex
1247  // scanner. It might not be easy.
1249  else
1250  return weightset()->one();
1251  }
1252 
1259  boost::optional<monomial_t>
1260  conv_monomial(std::istream& i, const char sep = '+') const
1261  {
1262 #define SKIP_SPACES() \
1263  while (isspace(i.peek())) \
1264  i.ignore()
1265 
1266  // Nothing to read: signal EOF as an empty result.
1267  SKIP_SPACES();
1268  if (i.peek() == EOF)
1269  return boost::none;
1270 
1271  // Possibly a weight in braces.
1272  bool weighted = i.peek() == langle;
1273  weight_t w = conv_weight(i);
1274 
1275  // Possibly, a label.
1276  SKIP_SPACES();
1277  auto l = conv_label(i, weighted, sep);
1278  require(l, *this, ": \\z is invalid for monomials");
1279  return monomial_t{*l, w};
1280 #undef SKIP_SPACES
1281  }
1282 
1291  value_t
1292  conv(std::istream& i, const char sep = '+') const
1293  {
1294  value_t res;
1295 #define SKIP_SPACES() \
1296  while (isspace(i.peek())) \
1297  i.ignore()
1298 
1299  do
1300  {
1301  // Possibly a weight in braces.
1302  SKIP_SPACES();
1303  bool weighted = i.peek() == langle;
1304  weight_t w = conv_weight(i);
1305 
1306  SKIP_SPACES();
1307  // Possibly, a label.
1308  // Handle label classes.
1309  if (i.peek() == '[')
1310  labelset()->convs(i, [this, &res, &w](const label_t& l)
1311  {
1312  add_here(res, l, w);
1313  });
1314  else if (auto l = conv_label(i, weighted, sep))
1315  {
1316  require(l, *this, ": \\z is invalid for monomials");
1317  add_here(res, *l, w);
1318  }
1319 
1320  // sep (e.g., '+'), or stop parsing.
1321  SKIP_SPACES();
1322  if (i.peek() == sep)
1323  i.ignore();
1324  else
1325  break;
1326  }
1327  while (true);
1328 #undef SKIP_SPACES
1329 
1330  return res;
1331  }
1332 
1334  std::ostream&
1335  print(const monomial_t& m, std::ostream& out,
1336  format fmt = {}) const
1337  {
1338  static bool parens = getenv("VCSN_PARENS");
1339  print_weight_(weight_of(m), out, fmt);
1340  if (parens)
1341  out << (fmt == format::latex ? "\\left(" : "(");
1342  labelset()->print(label_of(m), out, fmt.for_labels());
1343  if (parens)
1344  out << (fmt == format::latex ? "\\right)" : ")");
1345  return out;
1346  }
1347 
1354  std::ostream&
1355  print(const value_t& v, std::ostream& out,
1356  format fmt = {},
1357  const std::string& sep = " + ") const
1358  {
1359  if (is_zero(v))
1360  out << (fmt == format::latex ? "\\emptyset"
1361  : fmt == format::utf8 ? "∅"
1362  : "\\z");
1363  else
1364  {
1365  const auto s =
1366  (sep == " + "
1367  ? (fmt == format::latex ? std::string{" \\oplus "}
1368  : fmt == format::utf8 ? std::string{"⊕"}
1369  : sep)
1370  : sep);
1371  print_(v, out, fmt, s);
1372  }
1373  return out;
1374  }
1375 
1376  private:
1378  std::ostream&
1379  print_weight_(const weight_t w, std::ostream& out,
1380  format fmt) const
1381  {
1382  static bool parens = getenv("VCSN_PARENS");
1383  if (parens || weightset()->show_one() || !weightset()->is_one(w))
1384  {
1385  out << (fmt == format::latex ? "\\left\\langle "
1386  : fmt == format::utf8 ? "⟨"
1387  : "<");
1388  weightset()->print(w, out, fmt.for_weights());
1389  out << (fmt == format::latex ? "\\right\\rangle "
1390  : fmt == format::utf8 ? "⟩"
1391  : ">");
1392  }
1393  return out;
1394  }
1395 
1397  std::ostream&
1398  print_without_classes_(const value_t& v, std::ostream& out,
1399  format fmt,
1400  const std::string& sep) const
1401  {
1402  bool first = true;
1403  for (const auto& m: v)
1404  {
1405  if (!first)
1406  out << sep;
1407  first = false;
1408  print(m, out, fmt);
1409  }
1410  return out;
1411  }
1412 
1414  std::ostream&
1415  print_with_classes_(const value_t& v, std::ostream& out,
1416  format fmt,
1417  const std::string& sep) const
1418  {
1419  using std::begin;
1420  using std::end;
1421 
1422  // We can use a vector, as we know that the labels are already
1423  // sorted, and random access iteration will be handy below.
1424  using labels_t = std::vector<label_t>;
1425 
1426  // Cluster the letters per weight.
1427  auto per_weight = std::map<weight_t, labels_t,
1429  // No classes if the weights of the letters aren't all the same.
1430  for (const auto& m: v)
1431  if (!labelset()->is_one(label_of(m)))
1432  per_weight[weight_of(m)].emplace_back(label_of(m));
1433 
1434  // Sort the clusters per label.
1435  auto per_label = std::map<label_t,
1436  std::pair<weight_t, labels_t>,
1438  for (const auto& p: per_weight)
1439  // Split classes which are too small.
1440  if (p.second.size() < 3)
1441  for (auto l: p.second)
1442  per_label[l] = std::make_pair(p.first, labels_t{l});
1443  else
1444  per_label[detail::front(p.second)] = p;
1445 
1446  // Whether we must not issue a separator.
1447  bool first = true;
1448 
1449  // Print with classes. First, the constant-term.
1450  if (labelset()->is_one(label_of(detail::front(v))))
1451  {
1452  print(detail::front(v), out, fmt);
1453  first = false;
1454  }
1455 
1456  for (const auto& p: per_label)
1457  {
1458  if (!first)
1459  out << sep;
1460  first = false;
1461 
1462  // The weight.
1463  print_weight_(p.second.first, out, fmt);
1464 
1465  if (1 < p.second.second.size())
1466  // Print the character class. 'letters' are sorted, since
1467  // polynomials are shortlex-sorted on the labels.
1468  print_label_class(*labelset(), p.second.second,
1469  out, fmt.for_labels());
1470  else
1471  labelset()->print(detail::front(p.second.second),
1472  out, fmt.for_labels());
1473  }
1474  return out;
1475  }
1476 
1478  template <typename Ctx = context_t>
1480  std::ostream&>
1481  print_(const value_t& v, std::ostream& out,
1482  format fmt = {},
1483  const std::string& sep = " + ") const
1484  {
1485  return print_without_classes_(v, out, fmt, sep);
1486  }
1487 
1490  template <typename Ctx = context_t>
1492  std::ostream&>
1493  print_(const value_t& v, std::ostream& out,
1494  format fmt = {},
1495  const std::string& sep = " + ") const
1496  {
1497  // No classes if not at least 3 elements.
1498  if (sep == " + " || v.size() <= 2)
1499  return print_without_classes_(v, out, fmt, sep);
1500  else
1501  return print_with_classes_(v, out, fmt, sep);
1502  }
1503 
1504 
1505  private:
1507 
1509  constexpr static char langle = '<';
1511  constexpr static char rangle = '>';
1512  };
1513 
1514  template <typename Context,
1515  wet_kind_t Kind = detail::wet_kind<labelset_t_of<Context>,
1518  make_polynomialset(const Context& context)
1519  {
1520  return {context};
1521  }
1522 
1523  template <typename Ctx1, wet_kind_t Kind1,
1524  typename Ctx2, wet_kind_t Kind2>
1525  struct join_impl<polynomialset<Ctx1, Kind1>,
1526  polynomialset<Ctx2, Kind2>>
1527  {
1528  // Use the default kind.
1531  const polynomialset<Ctx2, Kind2>& ps2)
1532  {
1533  return {vcsn::join(ps1.context(), ps2.context())};
1534  }
1535  };
1536 
1537  template <typename Ctx1, wet_kind_t Kind1,
1538  typename WS2>
1539  struct join_impl<polynomialset<Ctx1, Kind1>, WS2>
1540  {
1541  using type
1542  = polynomialset<context<typename Ctx1::labelset_t,
1544  static type join(const polynomialset<Ctx1, Kind1>& ps1, const WS2& ws2)
1545  {
1546  return {*ps1.labelset(), vcsn::join(*ps1.weightset(), ws2)};
1547  }
1548  };
1549  }
1550 }
std::ostream & print(const value_t &v, std::ostream &out, format fmt={}, const std::string &sep=" + ") const
Print a value (a polynomial).
auto mul(const value_t &l, const value_t &r) const -> value_t
The product of polynomials l and r.
static ATTRIBUTE_PURE auto less_impl(const value_t &l, const value_t &r) -> std::enable_if_t< WetType!=wet_kind_t::bitset, bool >
const context_t & context() const
boost::optional< monomial_t > conv_monomial(std::istream &i, const char sep= '+') const
Read a monomial from a stream.
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
value_t conjunction(const value_t &l, const value_t &r) const
void clear(value_t &v)
Set to zero.
auto factor(const Aut &aut) -> decltype(::vcsn::copy(aut))
Definition: prefix.hh:106
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.
value_t abs(const value_t &v) const
Map all weights to their absolute value.
format for_labels() const
A copy of this format, but to print labels.
Definition: format.hh:42
value_t lgcd(const value_t &lhs, const value_t &rhs) const
LGCD between two polynomials.
static ATTRIBUTE_PURE bool monomial_equal(const monomial_t &lhs, const monomial_t &rhs)
static type join(const polynomialset< Ctx1, Kind1 > &ps1, const WS2 &ws2)
bool is_zero(const value_t &v) const
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.
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.
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:23
static constexpr star_status_t star_status()
static ATTRIBUTE_PURE auto hash_impl(const value_t &p) -> std::enable_if_t< WetType==wet_kind_t::bitset, size_t >
polynomialset_impl(const context_t &ctx)
value_t sub(const value_t &l, const value_t &r) const
The subtraction of polynomials l and r.
value_t add(const value_t &l, const value_t &r) const
The sum of polynomials l and r.
boost::optional< label_t > conv_label(std::istream &i, bool weighted, const char sep= '+') const
Read a label, if there is one.
value_t & add_here(value_t &v, const label_t &l, const weight_t k) const
v += l.
WeightSet::value_t operator()(const value_t &v) const
star_status_t
Definition: star-status.hh:5
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 compose.
value_t conv(std::istream &i, const char sep= '+') const
Read a polynomial from a stream.
symbol sname()
Definition: name.hh:65
monomial_t ldivide(const monomial_t &l, const monomial_t &r) const
typename context_t::labelset_ptr labelset_ptr
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 const monomial_t & monomial_one()
The unit monomial.
std::enable_if_t<!is_letterized_t< labelset_t_of< Aut > >{}, bool > is_letterized(const Aut &aut)
Definition: letterize.hh:161
ATTRIBUTE_NORETURN void raise_not_starrable(const WeightSet &ws, const typename WeightSet::value_t &w)
This value is not starrable.
Definition: raise.hh:100
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
Definition: traits.hh:63
value_t complement(const value_t &v) const
Complement this polynomial.
const labelset_ptr & labelset() const
void cross(Fun f)
Variadic Cartesian product of containers.
Definition: tuple.hh:273
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.
const weightset_ptr & weightset() const
value_t & sub_here(value_t &v, const monomial_t &m) const
v -= m.
value_t & add_here(value_t &l, const value_t &r) const
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.
auto label_of(const welement< Label, Weight > &m) -> decltype(m.label())
The label of a welement.
Definition: wet.hh:146
auto join(const ValueSet &vs) -> ValueSet
The join of a single valueset.
Definition: join.hh:44
Request the bitset implementation (bool weights).
A structure that implements the computation of join(V1, V2).
Definition: join.hh:18
value_t rdivide(const value_t &l, const value_t &r) const
auto norm(const value_t &v) const -> weight_t
The norm: the weight with which we should divide a polynomial to normalize it.
const value_t & zero() const
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:64
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:859
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.
Print as a parsable type string.
Definition: format.hh:26
std::ostream & print_weight_(const weight_t w, std::ostream &out, format fmt) const
Print a weight.
void require(Bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:91
value_t mul(const value_t &l, const monomial_t &rhs) const
Right product by a monomial.
z::value_t operator()(const value_t &v) const
decltype(join(std::declval< ValueSets >()...)) join_t
The type of the join of the ValueSets.
Definition: join.hh:78
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::ostream & print_with_classes_(const value_t &v, std::ostream &out, format fmt, const std::string &sep) const
Print a polynomial value with classes.
static self_t make(std::istream &is)
Build from the description in is.
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.
std::string bracketed(std::istream &i, char lbracket, char rbracket)
Extract the string which is here between lbracket and rbracket.
Definition: stream.cc:17
auto project() const
The polynomialset for tape Tape.
value_t lweight(const weight_t w, const value_t &v) const
Left exterior product.
value_t & add_here(value_t &v, const monomial_t &m) const
v += m.
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 constexpr bool is_commutative()
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 tuple(Polys &&...vs) const -> value_t
Build a tuple of polynomials: (e.E+f.F)|(g.G+h.H) => eg.
auto hash_value(const T &v) -> decltype(std::hash< T >
Following the naming convention of Boost.
Definition: functional.hh:30
constant< type_t::one, Context > one
Definition: fwd.hh:113
static type join(const polynomialset< Ctx1, Kind1 > &ps1, const polynomialset< Ctx2, Kind2 > &ps2)
wet_kind_t
Different implementations of wets.
Definition: wet.hh:197
labelset_t_of< context_t > labelset_t
static constexpr bool show_one()
#define SKIP_SPACES()
auto rweight(const value_t &v, const weight_t w) const -> value_t
Right exterior product.
label_t to_label(const value_t &v) const
Convert into a label.
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.
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.
static const value_t & one()
The unit polynomial.
static ATTRIBUTE_PURE size_t hash(const value_t &v)
value_t infiltrate(const value_t &l, const value_t &r) const
The infiltration of polynomials l and r.
static ATTRIBUTE_PURE auto hash_impl(const value_t &p) -> std::enable_if_t< WetType!=wet_kind_t::bitset, size_t >
monomial_t determinize(value_t v) const
"Determinize" this polynomial: turn into a monomial.
Definition: a-star.hh:8
static ATTRIBUTE_PURE bool equal(const value_t &l, const value_t &r)
Linear combination of labels: map labels to weights.
Definition: fwd.hh:41
typename detail::label_t_of_impl< base_t< ValueSet >>::type label_t_of
Definition: traits.hh:62
#define VCSN_REQUIRE(Cond,...)
A macro similar to require.
Definition: raise.hh:111
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.
weight_t normalize_here(value_t &v) const
Normalize v in place: compute the LGCD of the weights, ldivide the monomials with that factor...
value_t ldivide(const monomial_t &l, const value_t &r) const
Left division by a monomial.
An input/output format for valuesets.
Definition: format.hh:13
value_t transpose(const value_t &v) const
auto mul(const value_t &p, const label_t &l, const weight_t w) const -> value_t
The product of polynomials l and r.
value_t mul(const monomial_t &lhs, const value_t &v) const
Left product by a monomial.
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.
value_t & ldivide_here(const weight_t w, value_t &v) const
Left exterior division.
static ATTRIBUTE_PURE bool less(const value_t &l, const value_t &r)
static ATTRIBUTE_PURE size_t hash(const monomial_t &m, size_t res=0)
const weight_t get_weight(const value_t &v, const label_t &l) const ATTRIBUTE_PURE
Request the map implementation.
for(const auto &lm:l) for(const auto &rm return res
Functor to compare Values of ValueSets.
Definition: functional.hh:76
wet_of< context_t, Kind > value_t
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.
std::ostream & print(const monomial_t &m, std::ostream &out, format fmt={}) const
Print a monomial.
monomial_t mul(const monomial_t &l, const monomial_t &r) const
The product of monomials l and r.
static constexpr char langle
Left marker for weight in concrete syntax.
std::string to_string(direction d)
Conversion to string.
Definition: direction.cc:7
value_t rmul_label(const value_t &v, const label_t &rhs) const
Right product.
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 k.
void weight_set(welement< Label, Weight > &m, const Weight &w)
Set the weight of a welement.
Definition: wet.hh:162
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:324
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.
static ATTRIBUTE_PURE auto equal_impl(const value_t &l, const value_t &r) -> std::enable_if_t< WetType!=wet_kind_t::bitset, bool >
typename labelset_t::value_t label_t
Polynomials over labels.
Print as rich UTF-8 text, escaped.
Definition: format.hh:30
static constexpr bool has_lightening_weights()
void hash_combine(std::size_t &seed, const T &v)
Definition: functional.hh:48
auto project(const value_t &v) const
Extract a single tape.
weight_t_of< context_t > weight_t
auto weight_of(const welement< Label, Weight > &m) -> decltype(m.weight())
The weight of a welement.
Definition: wet.hh:154
polynomialset< Context, Kind > make_polynomialset(const Context &context)
value_t ldivide(const value_t &l, const value_t &r) const
value_t & rdivide_here(value_t &v, const weight_t w) const
Right exterior division.
value_t normalize(value_t res) const
Normalized v.
static value_t conv(self_t, const value_t &v)
Conversion from (this and) other weightsets.
typename value_t::value_type monomial_t
A pair .
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:67
typename context_t::weightset_ptr weightset_ptr
weightset_t_of< context_t > weightset_t
static ATTRIBUTE_PURE auto less_impl(const value_t &l, const value_t &r) -> std::enable_if_t< WetType==wet_kind_t::bitset, bool >
In the general case, normalize by the first (non null) weight.
value_t star(const value_t &v) const
The star of polynomial v.
Print for LaTeX.
Definition: format.hh:22
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
static constexpr char rangle
Right marker for weight in concrete syntax.
value_t conv(const polynomialset< C, K > &sps, const typename polynomialset< C, K >::value_t &v) const
Convert from another polynomialset to type_t.
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:90
Container::value_type front(const Container &container)
The first member of this Container.
Definition: algorithm.hh:68
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. ...
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.
auto compose(const value_t &l, const value_t &r) const -> std::enable_if_t< are_composable< Ctx, Ctx >
The composition of polynomials l and r when the context is a composable tupleset. ...
auto label_is_zero(const LabelSet &ls, const typename LabelSet::value_t *l) -> decltype(ls.is_zero(l), bool())
std::ostream & print_set(std::ostream &o, format fmt={}) const
static bool is_one(const value_t &v) ATTRIBUTE_PURE
Whether is the unit polynomial.
static symbol sname()
The static name.
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.
static ATTRIBUTE_PURE bool monomial_less(const monomial_t &lhs, const monomial_t &rhs)
value_t lmul_label(const label_t &lhs, const value_t &v) const
Left product by a label.
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
value_t & del_weight(value_t &v, const label_t &l) const
Remove the monomial of l in v.