Vcsn  2.1
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.
15 #include <vcsn/ctx/traits.hh>
16 #include <vcsn/misc/algorithm.hh> // front
17 #include <vcsn/misc/attributes.hh>
18 #include <vcsn/misc/functional.hh>
19 #include <vcsn/misc/math.hh>
20 #include <vcsn/misc/raise.hh>
21 #include <vcsn/misc/star-status.hh>
22 #include <vcsn/misc/stream.hh>
23 #include <vcsn/misc/wet.hh>
24 #include <vcsn/misc/zip-maps.hh>
25 #include <vcsn/weightset/fwd.hh>
26 #include <vcsn/weightset/z.hh>
27 
28 namespace vcsn
29 {
30  // http://llvm.org/bugs/show_bug.cgi?id=18571
31 #if defined __clang__
32 # pragma clang diagnostic push
33 # pragma clang diagnostic ignored "-Wunused-value"
34 #endif
35  template <typename LabelSet>
36  auto label_is_zero(const LabelSet& ls, const typename LabelSet::value_t* l)
37  -> decltype(ls.is_zero(l), bool())
38  {
39  return ls.is_zero(*l);
40  }
41 
42 #if defined __clang__
43 # pragma clang diagnostic pop
44 #endif
45 
46  template <typename LabelSet>
47  bool label_is_zero(const LabelSet&, ...)
48  ATTRIBUTE_CONST;
49 
50  template <typename LabelSet>
51  bool label_is_zero(const LabelSet&, ...)
52  {
53  return false;
54  }
55 
56  namespace detail
57  {
58  template <typename WeightSet>
60  : std::true_type
61  {};
62 
63  template <>
65  : std::false_type
66  {};
67 
68  template <typename Context, wet_kind_t Kind>
69  struct is_division_ring<polynomialset<Context, Kind>>
70  : std::false_type
71  {};
72 
75  template <typename Context, wet_kind_t Kind>
76  class polynomialset_impl
77  {
78  public:
80  using context_t = Context;
83 
84  using labelset_ptr = typename context_t::labelset_ptr;
85  using weightset_ptr = typename context_t::weightset_ptr;
87  using label_t = typename labelset_t::value_t;
89 
92  using monomial_t = typename value_t::value_type;
93 
94  polynomialset_impl() = delete;
95  polynomialset_impl(const polynomialset_impl&) = default;
97  : ctx_{ctx}
98  {}
99 
110  const self_t& self() const { return static_cast<const self_t&>(*this); }
111 
113  static symbol sname()
114  {
115  static symbol res("polynomialset<" + context_t::sname() + '>');
116  return res;
117  }
118 
119  const context_t& context() const { return ctx_; }
120  const labelset_ptr& labelset() const { return ctx_.labelset(); }
121  const weightset_ptr& weightset() const { return ctx_.weightset(); }
122 
123  static constexpr bool is_commutative() { return false; }
124 
126  value_t&
127  del_weight(value_t& v, const label_t& l) const
128  {
129  v.erase(l);
130  return v;
131  }
132 
135  value_t&
136  new_weight(value_t& v, const label_t& l, const weight_t w) const
137  {
138  assert(!weightset()->is_zero(w));
139  v.set(l, w);
140  return v;
141  }
142 
144  value_t&
145  set_weight(value_t& v, const label_t& l, const weight_t w) const
146  {
147  if (weightset()->is_zero(w))
148  return del_weight(v, l);
149  else
150  return new_weight(v, l, w);
151  }
152 
153  const weight_t
154  get_weight(const value_t& v, const label_t& l) const ATTRIBUTE_PURE
155  {
156  auto i = v.find(l);
157  if (i == v.end())
158  return weightset()->zero();
159  else
160  return weight_of(*i);
161  }
162 
163 
164  /*---------.
165  | clear. |
166  `---------*/
167 
169  void clear(value_t& v)
170  {
171  v.clear();
172  }
173 
174 
175  /*-------.
176  | add. |
177  `-------*/
178 
180  value_t&
181  add_here(value_t& v, const label_t& l, const weight_t k) const
182  {
183  if (!label_is_zero(*labelset(), &l))
184  {
185  auto i = v.find(l);
186  if (i == v.end())
187  {
188  set_weight(v, l, k);
189  }
190  else
191  {
192  // Do not use set_weight() because it would lookup l
193  // again and we already have the right iterator.
194  auto w2 = weightset()->add(weight_of(*i), k);
195  if (weightset()->is_zero(w2))
196  v.erase(i);
197  else
198  v.set(i, w2);
199  }
200  }
201  return v;
202  }
203 
205  value_t&
206  add_here(value_t& v, const monomial_t& m) const
207  {
208  return add_here(v, label_of(m), weight_of(m));
209  }
210 
212  template <wet_kind_t WetType>
213  auto
214  add_here_impl(value_t& l, const value_t& r) const
215  -> enable_if_t<!(WetType == wet_kind_t::bitset
216  && std::is_same<weightset_t, b>::value),
217  value_t&>
218  {
219  for (const auto& m: r)
220  add_here(l, m);
221  return l;
222  }
223 
225  template <wet_kind_t WetType>
226  auto
227  add_here_impl(value_t& l, const value_t& r) const
228  -> enable_if_t<WetType == wet_kind_t::bitset
229  && std::is_same<weightset_t, b>::value,
230  value_t&>
231  {
232  l.set() += r.set();
233  return l;
234  }
235 
236  value_t&
237  add_here(value_t& l, const value_t& r) const
238  {
239  return add_here_impl<value_t::kind>(l, r);
240  }
241 
243  value_t add(const value_t& l, const value_t& r) const
244  {
245  value_t res = l;
246  add_here(res, r);
247  return res;
248  }
249 
250 
251  /*-------.
252  | sub. |
253  `-------*/
254 
256  value_t&
257  sub_here(value_t& v, const monomial_t& m) const
258  {
259  if (!label_is_zero(*labelset(), &label_of(m)))
260  {
261  auto i = v.find(label_of(m));
262  if (i == v.end())
263  {
264  raise(sname(), ": sub_here: invalid arguments: ",
265  to_string(*this, v), ", ", to_string(*this, m));
266  }
267  else
268  {
269  // Do not use set_weight() because it would lookup w
270  // again and we already have the right iterator.
271  auto w2 = weightset()->sub(weight_of(*i), weight_of(m));
272  if (weightset()->is_zero(w2))
273  v.erase(i);
274  else
275  weight_set(*i, w2);
276  }
277  }
278  return v;
279  }
280 
282  value_t
283  sub(const value_t& l, const value_t& r) const
284  {
285  value_t res = l;
286  for (const auto& rm: r)
287  sub_here(res, rm);
288  return res;
289  }
290 
291 
292  /*-------.
293  | mul. |
294  `-------*/
295 
297  monomial_t
298  mul(const monomial_t& l, const monomial_t& r) const
299  {
300  return {labelset()->mul(label_of(l), label_of(r)),
301  weightset()->mul(weight_of(l), weight_of(r))};
302  }
303 
306  template <wet_kind_t WetType>
307  auto
308  mul_impl(const value_t& l, const value_t& r) const
309  -> enable_if_t<WetType != wet_kind_t::bitset,
310  value_t>
311  {
312  value_t res;
313  for (const auto& lm: l)
314  for (const auto& rm: r)
315  add_here(res,
316  labelset()->mul(label_of(lm), label_of(rm)),
317  weightset()->mul(weight_of(lm), weight_of(rm)));
318  return res;
319  }
320 
323  template <wet_kind_t WetType>
324  auto
325  mul_impl(const value_t& l, const value_t& r) const
326  -> enable_if_t<WetType == wet_kind_t::bitset,
327  value_t>
328  {
329  return l.set() & r.set();
330  }
331 
333  auto
334  mul(const value_t& l, const value_t& r) const
335  -> value_t
336  {
337  return mul_impl<value_t::kind>(l, r);
338  }
339 
341  auto
342  mul(const value_t& p, const label_t& l, const weight_t w) const
343  -> value_t
344  {
345  value_t res;
346  for (const auto& m: p)
347  add_here(res,
348  labelset()->mul(label_of(m), l),
349  weightset()->mul(weight_of(m), w));
350  return res;
351  }
352 
353 
354  /*---------------.
355  | conjunction. |
356  `---------------*/
357 
360  value_t
361  conjunction(const value_t& l, const value_t& r) const
362  {
363  value_t res;
364  for (const auto& lm: l)
365  for (const auto& rm: r)
366  add_here(res,
367  labelset()->conjunction(label_of(lm), label_of(rm)),
368  weightset()->mul(weight_of(lm), weight_of(rm)));
369  return res;
370  }
371 
374  value_t
375  infiltration(const value_t& l, const value_t& r) const
376  {
377  value_t res;
378  for (const auto& lm: l)
379  for (const auto& rm: r)
380  add_here(res,
381  labelset()->infiltration(label_of(lm), label_of(rm)),
382  weightset()->mul(weight_of(lm), weight_of(rm)));
383  return res;
384  }
385 
388  weight_t
389  scalar_product(const value_t& l, const value_t& r) const
390  {
391  weight_t res = weightset()->zero();
392  for (const auto& p: zip_maps<vcsn::as_tuple>(l, r))
393  res = weightset()->add(res,
394  weightset()->mul(weight_of(std::get<0>(p)),
395  weight_of(std::get<1>(p))));
396  return res;
397  }
398 
400  value_t
401  star(const value_t& v) const
402  {
403  // The only starrable polynomials are scalars (if they are
404  // starrable too).
405  auto s = v.size();
406  if (s == 0)
407  return one();
408  else if (s == 1)
409  {
410  auto i = v.find(labelset()->one());
411  if (i != v.end())
412  return {{i->first, weightset()->star(i->second)}};
413  }
414  raise(sname(), ": star: invalid value: ", to_string(*this, v));
415  }
416 
418  value_t
419  lmul(const weight_t w, const value_t& v) const
420  {
421  value_t res;
422  if (weightset()->is_one(w))
423  res = v;
424  else if (!weightset()->is_zero(w))
425  for (const auto& m: v)
426  add_here(res, label_of(m), weightset()->mul(w, weight_of(m)));
427  return res;
428  }
429 
431  value_t
432  lmul_label(const label_t& lhs, const value_t& v) const
433  {
434  value_t res;
435  for (const auto& m: v)
436  add_here(res,
437  labelset()->mul(lhs, label_of(m)),
438  weight_of(m));
439  return res;
440  }
441 
443  value_t
444  mul(const monomial_t& lhs, const value_t& v) const
445  {
446  value_t res;
447  for (const auto& m: v)
448  add_here(res,
449  labelset()->mul(label_of(lhs), label_of(m)),
450  weightset()->mul(weight_of(lhs), weight_of(m)));
451  return res;
452  }
453 
462  value_t
463  rmul(const value_t& v, const weight_t w) const
464  {
465  value_t res;
466  if (!weightset()->is_zero(w))
467  for (const auto& m: v)
468  add_here(res, labelset()->rmul(label_of(m), w), weight_of(m));
469  return res;
470  }
471 
473  value_t
474  rmul_label(const value_t& v, const label_t& rhs) const
475  {
476  value_t res;
477  for (const auto& lhs: v)
478  add_here(res,
479  labelset()->mul(label_of(lhs), rhs),
480  weight_of(lhs));
481  return res;
482  }
483 
485  value_t
486  mul(const value_t& l, const monomial_t& rhs) const
487  {
488  value_t res;
489  for (const auto& lhs: l)
490  add_here(res,
491  labelset()->mul(label_of(lhs), label_of(rhs)),
492  weightset()->mul(weight_of(lhs), weight_of(rhs)));
493  return res;
494  }
495 
496  value_t
497  rdiv(const value_t& l, const value_t& r) const
498  {
499  raise(sname(), ": rdiv: not implemented (",
500  to_string(*this, l), ", ", to_string(*this, r), ")");
501  }
502 
503  monomial_t
504  ldiv(const monomial_t& l, const monomial_t& r) const
505  {
506  return {labelset()->ldiv(label_of(l), label_of(r)),
507  weightset()->ldiv(weight_of(l), weight_of(r))};
508  }
509 
511  value_t
512  ldiv(const monomial_t& l, const value_t& r) const
513  {
514  value_t res;
515  for (const auto& m: r)
516  add_here(res, ldiv(l, m));
517  return res;
518  }
519 
520  value_t
521  ldiv(const value_t& l, const value_t& r) const
522  {
523  value_t res;
524  if (is_zero(l))
525  raise(sname(), ": ldiv: division by zero");
526  else
527  {
528  value_t remainder = r;
529 #if DEBUG
530  std::cerr << "ldiv(";
531  print(l, std::cerr) << ", ";
532  print(r, std::cerr) << "\n";
533 #endif
534  while (!is_zero(remainder))
535  {
536  auto factor = ldiv(detail::front(l), detail::front(remainder));
537 #if DEBUG
538  std::cerr << "factor = "; print(factor, std::cerr) << "\n";
539 #endif
540  add_here(res, factor);
541 #if DEBUG
542  std::cerr << "res = "; print(res, std::cerr) << "\n";
543  std::cerr << "sub = "; print(mul(l, factor), std::cerr) << "\n";
544 #endif
545  remainder = sub(remainder, mul(l, factor));
546 #if DEBUG
547  std::cerr << "rem = "; print(remainder, std::cerr) << "\n";
548 #endif
549  }
550 #if DEBUG
551  std::cerr << "ldiv(";
552  print(l, std::cerr) << ", ";
553  print(r, std::cerr) << ") = ";
554  print(res, std::cerr) << " rem: ";
555  print(remainder, std::cerr) << "\n";
556 #endif
557  if (!is_zero(remainder))
558  raise(sname(), ": ldiv: not implemented (",
559  to_string(*this, l), ", ", to_string(*this, r), ")");
560  }
561  return res;
562  }
563 
565  value_t&
566  ldiv_here(const weight_t w, value_t& v) const
567  {
568  if (!weightset()->is_one(w))
569  for (auto&& m: v)
570  weight_set(m, weightset()->ldiv(w, weight_of(m)));
571  return v;
572  }
573 
575  value_t&
576  rdiv_here(value_t& v, const weight_t w) const
577  {
578  if (!weightset()->is_one(w))
579  for (auto& m: v)
580  weight_set(m, weightset()->rdiv(weight_of(m), w));
581  return v;
582  }
583 
590  value_t lgcd(const value_t& lhs, const value_t& rhs) const
591  {
592  using std::begin;
593  using std::end;
594  value_t res;
595  // For each monomial, look for the matching GCD of the weight.
596  auto i = begin(lhs), i_end = end(lhs);
597  auto j = begin(rhs), j_end = end(rhs);
598  for (;
599  i != i_end && j != j_end
600  && labelset()->equal(i->first, j->first);
601  ++i, ++j)
602  res.set(i->first, weightset()->lgcd(i->second, j->second));
603  // If the sets of labels are different, the polynomials
604  // cannot be "colinear", and the GCD is just 1.
605  if (i != i_end || j != j_end)
606  res = one();
607  return res;
608  }
609 
610  /*--------.
611  | norm. |
612  `--------*/
613 
615  template <typename WeightSet, typename Dummy = void>
616  struct norm_
617  {
618  typename WeightSet::value_t operator()(const value_t& v) const
619  {
620  return weight_of(front(v));
621  }
622  const WeightSet& ws_;
623  };
624 
626  template <typename Dummy>
627  struct norm_<z, Dummy>
628  {
629  typename z::value_t operator()(const value_t& v) const
630  {
631  int sign = 0 < weight_of(detail::front(v)) ? 1 : -1;
632  auto res = abs(weight_of(detail::front(v)));
633  for (const auto& m: v)
634  res = z_.lgcd(res, abs(weight_of(m)));
635  res *= sign;
636  return res;
637  }
638  const z& z_;
639  };
640 
642  template <typename Ctx, wet_kind_t Knd, typename Dummy>
643  struct norm_<polynomialset<Ctx, Knd>, Dummy>
644  {
646 
647  typename ps_t::value_t operator()(const value_t& v) const
648  {
649  typename ps_t::value_t res = weight_of(detail::front(v));
650  for (const auto& p: v)
651  res = ps_.lgcd(res, weight_of(p));
652  return res;
653  }
654  const ps_t& ps_;
655  };
656 
659  auto norm(const value_t& v) const
660  -> weight_t
661  {
662  if (is_zero(v))
663  return weightset()->zero();
664  else
665  return norm_<weightset_t>{*weightset()}(v);
666  }
667 
668 
669  /*-------------.
670  | normalize. |
671  `-------------*/
672 
676  {
677  // Zero is in normal form, don't try to divide by zero.
678  auto res = norm(v);
679  if (!weightset()->is_zero(res))
680  ldiv_here(res, v);
681  return res;
682  }
683 
686  {
687  normalize_here(res);
688  return res;
689  }
690 
691 
692 
693  /*---------------.
694  | tuple(v...). |
695  `---------------*/
696 
699  template <typename... Polys>
700  auto
701  tuple(Polys&&... vs) const
702  -> value_t
703  {
704  auto res = value_t{};
705  detail::cross([&res, this](auto... ms)
706  {
707  this->add_here(res,
708  this->labelset()->tuple(ms.first...),
709  this->weightset()->mul(ms.second...));
710  },
711  std::forward<Polys>(vs)...);
712  return res;
713  }
714 
721  label_t to_label(const value_t& v) const
722  {
723  label_t res = labelset()->zero();
724  for (const auto& m: v)
725  res = labelset()->add(res, labelset()->lmul(weight_of(m), label_of(m)));
726  return res;
727  }
728 
733  {
734  weight_t w = normalize_here(v);
735  return {to_label(v), w};
736  }
737 
741  value_t complement(const value_t& v) const
742  {
743  return {{labelset()->complement(to_label(normalize(v))),
744  weightset()->one()}};
745  }
746 
747  /*---------------.
748  | equal(l, r). |
749  `---------------*/
750 
751  ATTRIBUTE_PURE
752  static bool monomial_equal(const monomial_t& lhs,
753  const monomial_t& rhs)
754  {
755  return (labelset_t::equal(label_of(lhs), label_of(rhs))
756  && weightset_t::equal(weight_of(lhs), weight_of(rhs)));
757  }
758 
759  template <wet_kind_t WetType>
760  ATTRIBUTE_PURE
761  static auto
762  equal_impl(const value_t& l, const value_t& r)
763  -> enable_if_t<WetType != wet_kind_t::bitset,
764  bool>
765  {
766  return boost::equal(l, r, monomial_equal);
767  }
768 
769  template <wet_kind_t WetType>
770  ATTRIBUTE_PURE
771  static auto
772  equal_impl(const value_t& l, const value_t& r)
773  -> enable_if_t<WetType == wet_kind_t::bitset,
774  bool>
775  {
776  return l.set() == r.set();
777  }
778 
779  ATTRIBUTE_PURE
780  static bool
781  equal(const value_t& l, const value_t& r)
782  {
783  return equal_impl<value_t::kind>(l, r);
784  }
785 
787  static const value_t& one()
788  {
789  static value_t res{monomial_one()};
790  return res;
791  }
792 
794  static const monomial_t& monomial_one()
795  {
797  return res;
798  }
799 
801  static bool is_one(const value_t& v) ATTRIBUTE_PURE
802  {
803  if (v.size() != 1)
804  return false;
805  auto i = v.find(labelset_t::one());
806  if (i == v.end())
807  return false;
808  return weightset_t::is_one(i->second);
809  }
810 
811  const value_t&
812  zero() const
813  {
814  static value_t res;
815  return res;
816  }
817 
818  bool
819  is_zero(const value_t& v) const
820  {
821  return v.empty();
822  }
823 
824  static constexpr bool show_one() { return false; }
825  static constexpr star_status_t star_status()
826  {
827  return weightset_t::star_status();
828  }
829 
831  static value_t
832  conv(self_t, const value_t& v)
833  {
834  return v;
835  }
836 
840  template <typename WS>
841  value_t
842  conv(const WS& ws, const typename WS::value_t& v) const
843  {
844  return {{labelset()->one(), weightset()->conv(ws, v)}};
845  }
846 
848  template <typename C, wet_kind_t K>
849  value_t
851  const typename polynomialset<C, K>::value_t& v) const
852  {
853  const typename C::labelset_t& sls = *sps.labelset();
854  const typename C::weightset_t& sws = *sps.weightset();
855  const labelset_t& tls = *labelset();
856  const weightset_t& tws = *weightset();
857  value_t res;
858  for (const auto& m: v)
859  add_here(res, tls.conv(sls, label_of(m)), tws.conv(sws, weight_of(m)));
860  return res;
861  }
862 
863 
864  /*--------------.
865  | less(l, r). |
866  `--------------*/
867 
868  ATTRIBUTE_PURE
869  static bool monomial_less(const monomial_t& lhs, const monomial_t& rhs)
870  {
871  if (labelset_t::less(label_of(lhs), label_of(rhs)))
872  return true;
873  else if (labelset_t::less(label_of(rhs), label_of(lhs)))
874  return false;
875  else
876  return weightset_t::less(weight_of(lhs), weight_of(rhs));
877  }
878 
879  template <wet_kind_t WetType>
880  ATTRIBUTE_PURE
881  static auto
882  less_impl(const value_t& l, const value_t& r)
883  -> enable_if_t<WetType != wet_kind_t::bitset,
884  bool>
885  {
886  return boost::range::lexicographical_compare(l, r, monomial_less);
887  }
888 
889  template <wet_kind_t WetType>
890  ATTRIBUTE_PURE
891  static auto
892  less_impl(const value_t& l, const value_t& r)
893  -> enable_if_t<WetType == wet_kind_t::bitset,
894  bool>
895  {
896  return l.set() < r.set();
897  }
898 
899  ATTRIBUTE_PURE
900  static bool
901  less(const value_t& l, const value_t& r)
902  {
903  return less_impl<value_t::kind>(l, r);
904  }
905 
906 
907  value_t
908  transpose(const value_t& v) const
909  {
910  value_t res;
911  for (const auto& i: v)
912  res.set(labelset()->transpose(label_of(i)),
913  weightset()->transpose(weight_of(i)));
914  return res;
915  }
916 
917 
918  /*--------.
919  | hash. |
920  `--------*/
921  ATTRIBUTE_PURE
922  static size_t hash(const monomial_t& m, size_t res = 0)
923  {
924  hash_combine(res, labelset_t::hash(label_of(m)));
925  hash_combine(res, weightset_t::hash(weight_of(m)));
926  return res;
927  }
928 
929  template <wet_kind_t WetType>
930  ATTRIBUTE_PURE
931  static auto
932  hash_impl(const value_t& p)
933  -> enable_if_t<WetType != wet_kind_t::bitset,
934  size_t>
935  {
936  size_t res = 0;
937  for (const auto& m: p)
938  res = hash(m, res);
939  return res;
940  }
941 
942  template <wet_kind_t WetType>
943  ATTRIBUTE_PURE
944  static auto
945  hash_impl(const value_t& p)
946  -> enable_if_t<WetType == wet_kind_t::bitset,
947  size_t>
948  {
949  return hash_value(p.set());
950  }
951 
952  ATTRIBUTE_PURE
953  static size_t hash(const value_t& v)
954  {
955  return hash_impl<value_t::kind>(v);
956  }
957 
958 
960  static self_t make(std::istream& is)
961  {
962  // name is, for instance, "polynomialset<lal_char(abcd), z>".
963  eat(is, "polynomialset<");
964  auto ctx = Context::make(is);
965  eat(is, '>');
966  return {ctx};
967  }
968 
969  std::ostream&
970  print_set(std::ostream& o, format fmt = {}) const
971  {
972  if (fmt == format::latex)
973  {
974  o << "\\mathsf{Poly}[";
975  labelset()->print_set(o, fmt);
976  o << " \\to ";
977  weightset()->print_set(o, fmt);
978  o << "]";
979  }
980  else
981  {
982  o << "polynomialset<";
983  labelset()->print_set(o, fmt);
984  o << "_";
985  weightset()->print_set(o, fmt);
986  o << ">";
987  }
988  return o;
989  }
990 
996  boost::optional<label_t>
997  conv_label(std::istream& i, bool weighted, const char sep = '+') const
998  {
999  int peek = i.peek();
1000  assert(peek != '[');
1001  if (peek == '\\')
1002  {
1003  i.ignore();
1004  if (i.peek() == 'z')
1005  {
1006  i.ignore();
1007  return boost::none;
1008  }
1009  else
1010  i.unget();
1011  }
1012 
1013  // The label is not \z.
1014  // Check if there is a label that comes. Or rather, check if
1015  // there is something else than EOF or the separator, in which
1016  // case it must be a label.
1017  label_t res;
1018  if (peek == EOF || peek == sep || isspace(peek))
1019  {
1020  // There is no label. This counts as '$', the special
1021  // label.
1022  //
1023  // Indeed, that's how we represent the initial and final
1024  // transitions: '$ -> 0 "<2>"'. Using the one label is
1025  // tempting, but it does not exist for lal_char for
1026  // instance. And it would be wrong to have '\e' when we
1027  // can, and '$' otherwise...
1028  //
1029  // However, we must have at least a weight: a completely
1030  // empty mononial ($ -> 0 "<2>,") is invalid.
1031  require(weighted,
1032  sname(), ": conv: invalid monomial: ",
1033  str_escape(peek),
1034  " (did you mean \\e or \\z?)");
1035  res = labelset()->special();
1036  }
1037  else
1038  res = labelset()->conv(i);
1039  return res;
1040  }
1041 
1043  weight_t
1044  conv_weight(std::istream& i) const
1045  {
1046  if (i.peek() == langle)
1047  // FIXME: convert to use conv(std::istream).
1048  //
1049  // The problem is when we have a rational expression as a
1050  // weight: in that case, conv expect to parse up to EOF, not
1051  // up to '>'. We first need to fix the parsing of expression
1052  // to work on a flow, to be able to use weightset()->conv
1053  // here. Which means to get back the stream from a Flex
1054  // scanner. It might not be easy.
1056  else
1057  return weightset()->one();
1058  }
1059 
1066  boost::optional<monomial_t>
1067  conv_monomial(std::istream& i, const char sep = '+') const
1068  {
1069 #define SKIP_SPACES() \
1070  while (isspace(i.peek())) \
1071  i.ignore()
1072 
1073  // Possibly a weight in braces.
1074  SKIP_SPACES();
1075  if (i.peek() == -1)
1076  return boost::none;
1077 
1078  bool weighted = i.peek() == langle;
1079  weight_t w = conv_weight(i);
1080 
1081  // Possibly, a label.
1082  SKIP_SPACES();
1083  auto l = conv_label(i, weighted, sep);
1084  require(l != boost::none,
1085  "\\z is invalid for monomials");
1086  return monomial_t{l.get(), w};
1087 #undef SKIP_SPACES
1088  }
1089 
1098  value_t
1099  conv(std::istream& i, const char sep = '+') const
1100  {
1101  value_t res;
1102 #define SKIP_SPACES() \
1103  while (isspace(i.peek())) \
1104  i.ignore()
1105 
1106  do
1107  {
1108  // Possibly a weight in braces.
1109  SKIP_SPACES();
1110  bool weighted = i.peek() == langle;
1111  weight_t w = conv_weight(i);
1112 
1113  SKIP_SPACES();
1114  // Possibly, a label.
1115  // Handle label classes.
1116  if (i.peek() == '[')
1117  labelset()->convs(i, [this, &res, &w](const label_t& l)
1118  {
1119  add_here(res, l, w);
1120  });
1121  else if (auto l = conv_label(i, weighted, sep))
1122  add_here(res, l.get(), w);
1123 
1124  // sep (e.g., '+'), or stop parsing.
1125  SKIP_SPACES();
1126  if (i.peek() == sep)
1127  i.ignore();
1128  else
1129  break;
1130  }
1131  while (true);
1132 #undef SKIP_SPACES
1133 
1134  return res;
1135  }
1136 
1138  std::ostream&
1139  print(const monomial_t& m, std::ostream& out,
1140  format fmt = {}) const
1141  {
1142  static bool parens = getenv("VCSN_PARENS");
1143  print_weight_(weight_of(m), out, fmt);
1144  if (parens)
1145  out << (fmt == format::latex ? "\\left(" : "(");
1146  labelset()->print(label_of(m), out, fmt.for_labels());
1147  if (parens)
1148  out << (fmt == format::latex ? "\\right)" : ")");
1149  return out;
1150  }
1151 
1158  std::ostream&
1159  print(const value_t& v, std::ostream& out,
1160  format fmt = {},
1161  const std::string& sep = " + ") const
1162  {
1163  bool latex = fmt == format::latex;
1164  if (is_zero(v))
1165  out << (latex ? "\\emptyset" : "\\z");
1166  else
1167  print_<context_t>(v, out, fmt,
1168  latex && sep == " + " ? " \\oplus " : sep);
1169  return out;
1170  }
1171 
1172  private:
1174  std::ostream&
1175  print_weight_(const weight_t w, std::ostream& out,
1176  format fmt) const
1177  {
1178  static bool parens = getenv("VCSN_PARENS");
1179  if (parens || weightset()->show_one() || !weightset()->is_one(w))
1180  {
1181  out << (fmt == format::latex ? "\\left\\langle " : std::string{langle});
1182  weightset()->print(w, out, fmt.for_weights());
1183  out << (fmt == format::latex ? "\\right\\rangle " : std::string{rangle});
1184  }
1185  return out;
1186  }
1187 
1189  std::ostream&
1190  print_without_classes_(const value_t& v, std::ostream& out,
1191  format fmt,
1192  const std::string& sep) const
1193  {
1194  bool first = true;
1195  for (const auto& m: v)
1196  {
1197  if (!first)
1198  out << sep;
1199  first = false;
1200  print(m, out, fmt);
1201  }
1202  return out;
1203  }
1204 
1206  std::ostream&
1207  print_with_classes_(const value_t& v, std::ostream& out,
1208  format fmt,
1209  const std::string& sep) const
1210  {
1211  using std::begin;
1212  using std::end;
1213 
1214  // No classes if not at least 3 elements.
1215  if (sep == " + " || v.size() <= 2)
1216  return print_without_classes_(v, out, fmt, sep);
1217 
1218  // No classes if the weights of the letters aren't all the same.
1219  auto first_letter
1220  = boost::find_if(v,
1221  [this](const monomial_t& m)
1222  {
1223  return !labelset()->is_one(label_of(m));
1224  });
1225  auto w = weight_of(*first_letter);
1226  if (!std::all_of(std::next(first_letter), end(v),
1227  [this, w](const monomial_t& m)
1228  {
1229  return weightset()->equal(weight_of(m), w);
1230  }))
1231  return print_without_classes_(v, out, fmt, sep);
1232 
1233  // Print with classes. First, the constant-term.
1234  if (first_letter != begin(v))
1235  {
1236  print(detail::front(v), out, fmt);
1237  if (1 < v.size())
1238  out << sep;
1239  }
1240 
1241  // The weight.
1242  print_weight_(w, out, fmt);
1243 
1244  // Gather the letters. We can use a vector, as we know that the
1245  // labels are already sorted, and random access iteration will
1246  // be handy below.
1247  std::vector<label_t> letters;
1248  for (const auto& m: v)
1249  if (!labelset()->is_one(label_of(m)))
1250  letters.push_back(label_of(m));
1251 
1252  // Print the character class. 'letters' are sorted, since
1253  // polynomials are shortlex-sorted on the labels.
1254  print_label_class(*labelset(), letters, out, fmt.for_labels());
1255  return out;
1256  }
1257 
1259  template <typename Ctx>
1261  std::ostream&>
1262  print_(const value_t& v, std::ostream& out,
1263  format fmt = {},
1264  const std::string& sep = " + ") const
1265  {
1266  return print_without_classes_(v, out, fmt, sep);
1267  }
1268 
1271  template <typename Ctx>
1273  std::ostream&>
1274  print_(const value_t& v, std::ostream& out,
1275  format fmt = {},
1276  const std::string& sep = " + ") const
1277  {
1278  return print_with_classes_(v, out, fmt, sep);
1279  }
1280 
1281 
1282  private:
1284 
1286  constexpr static char langle = '<';
1288  constexpr static char rangle = '>';
1289  };
1290 
1291 
1292  template <typename Ctx1, wet_kind_t Kind1,
1293  typename Ctx2, wet_kind_t Kind2>
1294  struct join_impl<polynomialset<Ctx1, Kind1>,
1295  polynomialset<Ctx2, Kind2>>
1296  {
1297  // Use the default kind.
1300  const polynomialset<Ctx2, Kind2>& ps2)
1301  {
1302  return {vcsn::join(ps1.context(), ps2.context())};
1303  }
1304  };
1305 
1306  template <typename Ctx1, wet_kind_t Kind1,
1307  typename WS2>
1308  struct join_impl<polynomialset<Ctx1, Kind1>, WS2>
1309  {
1310  using type
1311  = polynomialset<context<typename Ctx1::labelset_t,
1313  static type join(const polynomialset<Ctx1, Kind1>& ps1, const WS2& ws2)
1314  {
1315  return {*ps1.labelset(), vcsn::join(*ps1.weightset(), ws2)};
1316  }
1317  };
1318  }
1319 }
static constexpr bool show_one()
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:329
value_t mul(const value_t &l, const monomial_t &rhs) const
Right product by a monomial.
std::ostream & str_escape(std::ostream &os, const std::string &str)
Output a string, escaping special characters.
Definition: escape.cc:43
Container::value_type front(const Container &container)
The first member of this Container.
Definition: algorithm.hh:57
value_t complement(const value_t &v) const
Complement this polynomial.
static symbol sname()
The static name.
static constexpr char rangle
Right marker for weight in concrete syntax.
auto factor(const Aut &aut) -> decltype(::vcsn::copy(aut))
Definition: prefix.hh:106
format for_labels() const
A copy of this format, but to print labels.
Definition: format.hh:34
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.
value_t & add_here(value_t &l, const value_t &r) const
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
monomial_t determinize(value_t v) const
"Determinize" this polynomial: turn into a monomial.
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 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_set(std::ostream &o, format fmt={}) const
weightset_t_of< context_t > weightset_t
boost::optional< monomial_t > conv_monomial(std::istream &i, const char sep= '+') const
Read a monomial from a stream.
const weightset_ptr & weightset() const
auto label_of(const welement< Label, Weight > &m) -> decltype(m.label())
Definition: wet.hh:125
void clear(value_t &v)
Set to zero.
A structure that implements the computation of join(V1, V2).
Definition: join.hh:18
static ATTRIBUTE_PURE size_t hash(const monomial_t &m, size_t res=0)
auto join(const ValueSet &vs) -> ValueSet
The join of a single valueset.
Definition: join.hh:44
std::istringstream is
The input stream: the specification to translate.
Definition: translate.cc:372
weight_t_of< context_t > weight_t
wet_of< context_t, Kind > value_t
vcsn::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. ...
auto mul(const value_t &p, const label_t &l, const weight_t w) const -> value_t
The product of polynomials l and r.
polynomialset_impl(const context_t &ctx)
weight_t scalar_product(const value_t &l, const value_t &r) const
The sum of the weights of the common labels.
auto tuple(Polys &&...vs) const -> value_t
Build a tuple of polynomials: (e.E+f.F)|(g.G+h.H) => eg.
static ATTRIBUTE_PURE auto less_impl(const value_t &l, const value_t &r) -> enable_if_t< WetType==wet_kind_t::bitset, bool >
value_t sub(const value_t &l, const value_t &r) const
The subtraction of polynomials l and r.
static ATTRIBUTE_PURE auto less_impl(const value_t &l, const value_t &r) -> enable_if_t< WetType!=wet_kind_t::bitset, bool >
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:37
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:51
value_t & del_weight(value_t &v, const label_t &l) const
Remove the monomial of l in v.
value_t conv(std::istream &i, const char sep= '+') const
Read a polynomial from a stream.
typename std::enable_if< Cond, T >::type enable_if_t
Definition: type_traits.hh:16
static ATTRIBUTE_PURE auto hash_impl(const value_t &p) -> enable_if_t< WetType!=wet_kind_t::bitset, size_t >
value_t star(const value_t &v) const
The star of polynomial v.
labelset_t_of< context_t > labelset_t
z::value_t operator()(const value_t &v) const
weight_t conv_weight(std::istream &i) const
Read a weight, if there is one, bracketed.
label_t to_label(const value_t &v) const
Convert into a label.
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.
wet_kind_t
Definition: wet.hh:168
const weight_t get_weight(const value_t &v, const label_t &l) const ATTRIBUTE_PURE
static const monomial_t & monomial_one()
The unit monomial.
auto hash_value(const T &v) -> decltype(std::hash< T >
Following the naming convention of Boost.
Definition: functional.hh:63
typename value_t::value_type monomial_t
A pair .
static ATTRIBUTE_PURE size_t hash(const value_t &v)
static constexpr char langle
Left marker for weight in concrete syntax.
static type join(const polynomialset< Ctx1, Kind1 > &ps1, const polynomialset< Ctx2, Kind2 > &ps2)
void hash_combine(std::size_t &seed, const T &v)
Definition: functional.hh:32
value_t lmul_label(const label_t &lhs, const value_t &v) const
Left product by a label.
auto mul_impl(const value_t &l, const value_t &r) const -> enable_if_t< WetType!=wet_kind_t::bitset, value_t >
The product of polynomials l and r.
static ATTRIBUTE_PURE bool equal(const value_t &l, const value_t &r)
static dyn::context ctx(const driver &d)
Get the context of the driver.
Definition: parse.cc:80
typename context_t::labelset_ptr labelset_ptr
value_t conv(const polynomialset< C, K > &sps, const typename polynomialset< C, K >::value_t &v) const
Convert from another polynomialset to type_t.
An input/output format.
Definition: format.hh:11
weight_t normalize_here(value_t &v) const
Normalize v in place: compute the LGCD of the weights, ldiv the monomials with that factor...
value_t conjunction(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) -> enable_if_t< WetType==wet_kind_t::bitset, bool >
vcsn::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.
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
value_t normalize(value_t res) const
Normalized v.
static self_t make(std::istream &is)
Build from the description in is.
static ATTRIBUTE_PURE auto equal_impl(const value_t &l, const value_t &r) -> enable_if_t< WetType!=wet_kind_t::bitset, bool >
typename labelset_t::value_t label_t
Polynomials over labels.
value_t & add_here(value_t &v, const monomial_t &m) const
v += m.
decltype(join(std::declval< ValueSets >()...)) join_t
The type of the join of the ValueSets.
Definition: join.hh:79
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
Definition: traits.hh:47
auto weight_of(const welement< Label, Weight > &m) -> decltype(m.weight())
Definition: wet.hh:132
const context_t & context() const
static ATTRIBUTE_PURE auto hash_impl(const value_t &p) -> enable_if_t< WetType==wet_kind_t::bitset, size_t >
void require(bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:75
WeightSet::value_t operator()(const value_t &v) const
auto add_here_impl(value_t &l, const value_t &r) const -> enable_if_t<!(WetType==wet_kind_t::bitset &&std::is_same< weightset_t, b >::value), value_t & >
v += p, default case.
std::string to_string(direction d)
Conversion to string.
Definition: direction.cc:7
auto add_here_impl(value_t &l, const value_t &r) const -> enable_if_t< WetType==wet_kind_t::bitset &&std::is_same< weightset_t, b >::value, value_t & >
v += p, B and bitsets.
value_t ldiv(const value_t &l, const value_t &r) const
auto mul_impl(const value_t &l, const value_t &r) const -> enable_if_t< WetType==wet_kind_t::bitset, value_t >
The product of polynomials l and r.
auto mul(const value_t &l, const value_t &r) const -> value_t
The product of polynomials l and r.
static const value_t & one()
The unit polynomial.
symbol sname()
Definition: name.hh:67
static ATTRIBUTE_PURE bool monomial_less(const monomial_t &lhs, const monomial_t &rhs)
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:23
std::ostream & print(const value_t &v, std::ostream &out, format fmt={}, const std::string &sep=" + ") const
Print a value (a polynomial).
value_t mul(const monomial_t &lhs, const value_t &v) const
Left product by a monomial.
typename context_t::weightset_ptr weightset_ptr
const value_t & zero() const
vcsn::enable_if_t<!is_letterized_t< labelset_t_of< Aut > >{}, bool > is_letterized(const Aut &aut)
Definition: letterize.hh:162
std::ostream & print_weight_(const weight_t w, std::ostream &out, format fmt) const
Print a weight.
star_status_t
Definition: star-status.hh:5
value_t transpose(const value_t &v) const
Linear combination of labels: map labels to weights.
Definition: fwd.hh:41
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:791
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 type join(const polynomialset< Ctx1, Kind1 > &ps1, const WS2 &ws2)
In the general case, normalize by the first (non null) weight.
value_t lgcd(const value_t &lhs, const value_t &rhs) const
LGCD between two polynomials.
const labelset_ptr & labelset() const
value_t lmul(const weight_t w, const value_t &v) const
Left exterior product.
static ATTRIBUTE_PURE bool less(const value_t &l, const value_t &r)
value_t ldiv(const monomial_t &l, const value_t &r) const
Left division by a monomial.
value_t rdiv(const value_t &l, const value_t &r) const
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.
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:28
void weight_set(welement< Label, Weight > &m, const Weight &w)
Definition: wet.hh:139
value_t & sub_here(value_t &v, const monomial_t &m) const
v -= m.
static constexpr star_status_t star_status()
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 bool is_one(const value_t &v) ATTRIBUTE_PURE
Whether is the unit polynomial.
value_t add(const value_t &l, const value_t &r) const
The sum of polynomials l and r.
value_t rmul(const value_t &v, const weight_t w) const
Right exterior product.
value_t & add_here(value_t &v, const label_t &l, const weight_t k) const
v += l.
value_t & rdiv_here(value_t &v, const weight_t w) const
Right exterior division.
std::string bracketed(std::istream &i, char lbracket, char rbracket)
Extract the string which is here between lbracket and rbracket.
Definition: stream.cc:17
value_t & ldiv_here(const weight_t w, value_t &v) const
Left exterior division.
value_t infiltration(const value_t &l, const value_t &r) const
The infiltration of polynomials l and r.
void cross(Fun f)
Variadic Cartesian product of containers.
Definition: tuple.hh:207
#define SKIP_SPACES()
static value_t conv(self_t, const value_t &v)
Conversion from (this and) other weightsets.
constant< type_t::one, Context > one
Definition: fwd.hh:111
static constexpr bool is_commutative()
value_t rmul_label(const value_t &v, const label_t &rhs) const
Right product.
static ATTRIBUTE_PURE bool monomial_equal(const monomial_t &lhs, const monomial_t &rhs)
bool is_zero(const value_t &v) const
monomial_t ldiv(const monomial_t &l, const monomial_t &r) const
auto label_is_zero(const LabelSet &ls, const typename LabelSet::value_t *l) -> decltype(ls.is_zero(l), bool())
typename detail::weight_t_of_impl< base_t< ValueSet >>::type weight_t_of
Definition: traits.hh:50
boost::optional< label_t > conv_label(std::istream &i, bool weighted, const char sep= '+') const
Read a label, if there is one.