piranha  0.10
kronecker_monomial.hpp
1 /* Copyright 2009-2017 Francesco Biscani (bluescarni@gmail.com)
2 
3 This file is part of the Piranha library.
4 
5 The Piranha library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8  * the GNU Lesser General Public License as published by the Free
9  Software Foundation; either version 3 of the License, or (at your
10  option) any later version.
11 
12 or
13 
14  * the GNU General Public License as published by the Free Software
15  Foundation; either version 3 of the License, or (at your option) any
16  later version.
17 
18 or both in parallel, as here.
19 
20 The Piranha library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the Piranha library. If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #ifndef PIRANHA_KRONECKER_MONOMIAL_HPP
30 #define PIRANHA_KRONECKER_MONOMIAL_HPP
31 
32 #include <algorithm>
33 #include <array>
34 #include <cstddef>
35 #include <cstdint>
36 #include <functional>
37 #include <initializer_list>
38 #include <iostream>
39 #include <iterator>
40 #include <limits>
41 #include <sstream>
42 #include <stdexcept>
43 #include <string>
44 #include <type_traits>
45 #include <utility>
46 #include <vector>
47 
48 #include <piranha/config.hpp>
49 #include <piranha/detail/cf_mult_impl.hpp>
50 #include <piranha/detail/km_commons.hpp>
51 #include <piranha/detail/monomial_common.hpp>
52 #include <piranha/detail/prepare_for_print.hpp>
53 #include <piranha/detail/safe_integral_adder.hpp>
54 #include <piranha/exceptions.hpp>
55 #include <piranha/is_cf.hpp>
56 #include <piranha/is_key.hpp>
57 #include <piranha/kronecker_array.hpp>
58 #include <piranha/math.hpp>
59 #include <piranha/mp_integer.hpp>
60 #include <piranha/mp_rational.hpp>
61 #include <piranha/pow.hpp>
62 #include <piranha/s11n.hpp>
63 #include <piranha/safe_cast.hpp>
64 #include <piranha/static_vector.hpp>
65 #include <piranha/symbol_utils.hpp>
66 #include <piranha/term.hpp>
67 #include <piranha/type_traits.hpp>
68 
69 namespace piranha
70 {
71 
72 inline namespace impl
73 {
74 
75 // Check the size of a k_monomial after deserialization (s1) against the
76 // size of the reference symbol set (s2).
77 template <typename T, typename U>
78 inline void k_monomial_load_check_sizes(T s1, U s2)
79 {
80  static_assert(
81  conjunction<std::is_integral<T>, std::is_unsigned<T>, std::is_integral<U>, std::is_unsigned<U>>::value,
82  "Type error: this function requires unsigned integral types as input.");
83  if (unlikely(s1 != s2)) {
84  piranha_throw(std::invalid_argument, "invalid size detected in the deserialization of a Kronercker "
85  "monomial: the deserialized size ("
86  + std::to_string(s1)
87  + ") differs from the size of the reference symbol set ("
88  + std::to_string(s2) + ")");
89  }
90 }
91 }
92 
94 
114 // NOTE:
115 // - consider abstracting the km_commons in a class and use it both here and in rtkm.
116 // - it might be better to rework the machinery for the unpacking. An idea is to just use std::vectors
117 // with TLS, and have the unpack function take retval as mutable ref rather than returning a vector.
118 template <typename T = std::make_signed<std::size_t>::type>
120 {
121 public:
123  using value_type = T;
124 
125 private:
126  using ka = kronecker_array<T>;
127 
128 public:
130 
134  using size_type = typename ka::size_type;
136  // NOTE: this essentially defines a maximum number of small ints that can be packed in m_value,
137  // as we always need to pass through pack/unpack. In practice, it does not matter: in current
138  // architectures the bit width limit will result in kronecker array's limits to be smaller than
139  // 255 items.
142  static const std::size_t multiply_arity = 1u;
144 
147  kronecker_monomial() : m_value(0) {}
149  kronecker_monomial(const kronecker_monomial &) = default;
152 
153 private:
154  // Enablers for the ctor from container.
155  template <typename U>
156  using container_ctor_enabler
157  = enable_if_t<conjunction<has_input_begin_end<const U>,
158  has_safe_cast<T, typename std::iterator_traits<decltype(
159  std::begin(std::declval<const U &>()))>::value_type>>::value,
160  int>;
161  // Implementation of the ctor from range.
162  template <typename Iterator>
163  typename v_type::size_type construct_from_range(Iterator begin, Iterator end)
164  {
165  v_type tmp;
166  std::transform(begin, end, std::back_inserter(tmp),
167  [](const uncvref_t<decltype(*begin)> &v) { return safe_cast<T>(v); });
168  m_value = ka::encode(tmp);
169  return tmp.size();
170  }
171 
172 public:
174 
187  template <typename U, container_ctor_enabler<U> = 0>
188  explicit kronecker_monomial(const U &c) : kronecker_monomial(std::begin(c), std::end(c))
189  {
190  }
191 
192 private:
193  template <typename U>
194  using init_list_ctor_enabler = container_ctor_enabler<std::initializer_list<U>>;
195 
196 public:
198 
206  template <typename U, init_list_ctor_enabler<U> = 0>
207  explicit kronecker_monomial(std::initializer_list<U> list) : kronecker_monomial(list.begin(), list.end())
208  {
209  }
210 
211 private:
212  template <typename Iterator>
213  using it_ctor_enabler
214  = enable_if_t<conjunction<is_input_iterator<Iterator>,
215  has_safe_cast<T, typename std::iterator_traits<Iterator>::value_type>>::value,
216  int>;
217 
218 public:
220 
238  template <typename Iterator, it_ctor_enabler<Iterator> = 0>
239  explicit kronecker_monomial(Iterator begin, Iterator end)
240  {
241  construct_from_range(begin, end);
242  }
244 
260  template <typename Iterator, it_ctor_enabler<Iterator> = 0>
261  explicit kronecker_monomial(Iterator begin, Iterator end, const symbol_fset &s)
262  {
263  const auto c_size = construct_from_range(begin, end);
264  if (unlikely(c_size != s.size())) {
265  piranha_throw(std::invalid_argument, "the Kronecker monomial constructor from range and symbol set "
266  "yielded an invalid monomial: the range length ("
267  + std::to_string(c_size)
268  + ") differs from the size of the symbol set ("
269  + std::to_string(s.size()) + ")");
270  }
271  }
273 
278 
284  explicit kronecker_monomial(const kronecker_monomial &other, const symbol_fset &) : kronecker_monomial(other) {}
286 
292  explicit kronecker_monomial(const T &n) : m_value(n) {}
295  {
300  }
302 
307  kronecker_monomial &operator=(const kronecker_monomial &other) = default;
309 
314  kronecker_monomial &operator=(kronecker_monomial &&other) = default;
316 
319  void set_int(const T &n)
320  {
321  m_value = n;
322  }
324 
327  T get_int() const
328  {
329  return m_value;
330  }
332 
346  bool is_compatible(const symbol_fset &args) const noexcept
347  {
348  // NOTE: the idea here is to avoid unpack()ing for performance reasons: these checks
349  // are already part of unpack(), and that's why unpack() is used instead of is_compatible()
350  // in other methods.
351  const auto s = args.size();
352  // No args means the value must also be zero.
353  if (!s) {
354  return !m_value;
355  }
356  const auto &limits = ka::get_limits();
357  // If we overflow the maximum size available, we cannot use this object as key in series.
358  if (s >= limits.size()) {
359  return false;
360  }
361  const auto &l = limits[static_cast<decltype(limits.size())>(s)];
362  // Value is compatible if it is within the bounds for the given size.
363  return (m_value >= std::get<1u>(l) && m_value <= std::get<2u>(l));
364  }
366 
371  bool is_zero(const symbol_fset &) const noexcept
372  {
373  return false;
374  }
376 
402  {
403  return kronecker_monomial(detail::km_merge_symbols<v_type, ka>(ins_map, args, m_value));
404  }
406 
409  bool is_unitary(const symbol_fset &) const
410  {
411  // A kronecker code will be zero if all components are zero.
412  return !m_value;
413  }
414 
415 private:
416  // Degree utils.
417  using degree_type = add_t<T, T>;
418 
419 public:
421 
432  degree_type degree(const symbol_fset &args) const
433  {
434  const auto tmp = unpack(args);
435  // NOTE: this should be guaranteed by the unpack function.
436  piranha_assert(tmp.size() == args.size());
437  degree_type retval(0);
438  for (const auto &x : tmp) {
439  // NOTE: here it might be possible to demonstrate that overflow can
440  // never occur, and that we can use a normal integral addition.
441  detail::safe_integral_adder(retval, static_cast<degree_type>(x));
442  }
443  return retval;
444  }
446 
453  degree_type ldegree(const symbol_fset &args) const
454  {
455  return degree(args);
456  }
458 
473  degree_type degree(const symbol_idx_fset &p, const symbol_fset &args) const
474  {
475  const auto tmp = unpack(args);
476  piranha_assert(tmp.size() == args.size());
477  if (unlikely(p.size() && *p.rbegin() >= tmp.size())) {
478  piranha_throw(std::invalid_argument, "the largest value in the positions set for the computation of the "
479  "partial degree of a Kronecker monomial is "
480  + std::to_string(*p.rbegin())
481  + ", but the monomial has a size of only "
482  + std::to_string(tmp.size()));
483  }
484  degree_type retval(0);
485  for (auto idx : p) {
486  detail::safe_integral_adder(retval, static_cast<degree_type>(tmp[static_cast<decltype(tmp.size())>(idx)]));
487  }
488  return retval;
489  }
491 
499  degree_type ldegree(const symbol_idx_fset &p, const symbol_fset &args) const
500  {
501  return degree(p, args);
502  }
503 
504 private:
505  // Enabler for multiply().
506  template <typename Cf>
507  using multiply_enabler = enable_if_t<has_mul3<Cf>::value, int>;
508 
509 public:
511 
529  template <typename Cf, multiply_enabler<Cf> = 0>
530  static void multiply(std::array<term<Cf, kronecker_monomial>, multiply_arity> &res,
532  const symbol_fset &)
533  {
534  // Coefficient first.
535  cf_mult_impl(res[0u].m_cf, t1.m_cf, t2.m_cf);
536  // Now the key.
537  math::add3(res[0u].m_key.m_value, t1.m_key.get_int(), t2.m_key.get_int());
538  }
540 
543  std::size_t hash() const
544  {
545  return static_cast<std::size_t>(m_value);
546  }
548 
554  bool operator==(const kronecker_monomial &other) const
555  {
556  return m_value == other.m_value;
557  }
559 
564  bool operator!=(const kronecker_monomial &other) const
565  {
566  return !operator==(other);
567  }
569 
581  std::pair<bool, symbol_idx> is_linear(const symbol_fset &args) const
582  {
583  const auto v = unpack(args);
584  const auto size = v.size();
585  decltype(v.size()) n_linear = 0, candidate = 0;
586  for (decltype(v.size()) i = 0; i < size; ++i) {
587  if (!v[i]) {
588  continue;
589  }
590  if (v[i] != T(1)) {
591  return std::make_pair(false, symbol_idx{0});
592  }
593  candidate = i;
594  ++n_linear;
595  }
596  if (n_linear != 1u) {
597  return std::make_pair(false, symbol_idx{0});
598  }
599  return std::make_pair(true, symbol_idx{candidate});
600  }
601 
602 private:
603  // Enabler for pow.
604  template <typename U>
605  using pow_enabler = monomial_pow_enabler<T, U>;
606 
607 public:
609 
634  template <typename U, pow_enabler<U> = 0>
635  kronecker_monomial pow(const U &x, const symbol_fset &args) const
636  {
637  auto v = unpack(args);
638  for (auto &n : v) {
639  monomial_pow_mult_exp(n, n, x, monomial_pow_dispatcher<T, U>{});
640  }
641  return kronecker_monomial(ka::encode(v));
642  }
644 
656  v_type unpack(const symbol_fset &args) const
657  {
658  return detail::km_unpack<v_type, ka>(args, m_value);
659  }
661 
669  void print(std::ostream &os, const symbol_fset &args) const
670  {
671  const auto tmp = unpack(args);
672  piranha_assert(tmp.size() == args.size());
673  bool empty_output = true;
674  auto it_args = args.begin();
675  for (decltype(tmp.size()) i = 0u; i < tmp.size(); ++i, ++it_args) {
676  if (tmp[i] != T(0)) {
677  if (!empty_output) {
678  os << '*';
679  }
680  os << *it_args;
681  empty_output = false;
682  if (tmp[i] != T(1)) {
683  os << "**" << detail::prepare_for_print(tmp[i]);
684  }
685  }
686  }
687  }
689 
697  void print_tex(std::ostream &os, const symbol_fset &args) const
698  {
699  const auto tmp = unpack(args);
700  std::ostringstream oss_num, oss_den, *cur_oss;
701  T cur_value;
702  auto it_args = args.begin();
703  for (decltype(tmp.size()) i = 0u; i < tmp.size(); ++i, ++it_args) {
704  cur_value = tmp[i];
705  if (cur_value != T(0)) {
706  // NOTE: here negate() is safe because of the symmetry in kronecker_array.
707  cur_oss = (cur_value > T(0)) ? &oss_num : (math::negate(cur_value), &oss_den);
708  *cur_oss << "{" << *it_args << "}";
709  if (cur_value != T(1)) {
710  *cur_oss << "^{" << static_cast<long long>(cur_value) << "}";
711  }
712  }
713  }
714  const std::string num_str = oss_num.str(), den_str = oss_den.str();
715  if (!num_str.empty() && !den_str.empty()) {
716  os << "\\frac{" << num_str << "}{" << den_str << "}";
717  } else if (!num_str.empty() && den_str.empty()) {
718  os << num_str;
719  } else if (num_str.empty() && !den_str.empty()) {
720  os << "\\frac{1}{" << den_str << "}";
721  }
722  }
724 
740  std::pair<T, kronecker_monomial> partial(const symbol_idx &p, const symbol_fset &args) const
741  {
742  auto v = unpack(args);
743  if (p >= args.size() || v[static_cast<decltype(v.size())>(p)] == T(0)) {
744  // Derivative wrt a variable not in the monomial: the position is outside the bounds, or it refers to a
745  // variable with zero exponent.
746  return std::make_pair(T(0), kronecker_monomial{args});
747  }
748  auto v_b = v.begin();
749  // The original exponent.
750  const T n(v_b[p]);
751  // Decrement the exponent in the monomial.
752  // NOTE: maybe replace with the safe integral subber, eventually.
753  if (unlikely(n == std::numeric_limits<T>::min())) {
754  piranha_throw(std::overflow_error, "negative overflow error in the calculation of the "
755  "partial derivative of a Kronecker monomial");
756  }
757  v_b[p] = static_cast<T>(n - T(1));
758  return std::make_pair(n, kronecker_monomial(ka::encode(v)));
759  }
761 
780  std::pair<T, kronecker_monomial> integrate(const std::string &s, const symbol_fset &args) const
781  {
782  const v_type v = unpack(args);
783  v_type retval;
784  T expo(0);
785  auto it_args = args.begin();
786  for (decltype(v.size()) i = 0; i < v.size(); ++i, ++it_args) {
787  const auto &cur_sym = *it_args;
788  if (expo == T(0) && s < cur_sym) {
789  // If we went past the position of s in args and still we
790  // have not performed the integration, it means that we need to add
791  // a new exponent.
792  retval.push_back(T(1));
793  expo = T(1);
794  }
795  retval.push_back(v[i]);
796  if (cur_sym == s) {
797  // NOTE: here using i is safe: if retval gained an extra exponent in the condition above,
798  // we are never going to land here as cur_sym is at this point never going to be s.
799  if (unlikely(retval[i] == std::numeric_limits<T>::max())) {
801  std::overflow_error,
802  "positive overflow error in the calculation of the antiderivative of a Kronecker monomial");
803  }
804  // Do the addition and check for zero later, to detect -1 expo.
805  retval[i] = static_cast<T>(retval[i] + T(1));
806  if (unlikely(math::is_zero(retval[i]))) {
807  piranha_throw(std::invalid_argument,
808  "unable to perform Kronecker monomial integration: a negative "
809  "unitary exponent was encountered in correspondence of the variable '"
810  + cur_sym + "'");
811  }
812  expo = retval[i];
813  }
814  }
815  // If expo is still zero, it means we need to add a new exponent at the end.
816  if (expo == T(0)) {
817  retval.push_back(T(1));
818  expo = T(1);
819  }
820  return std::make_pair(expo, kronecker_monomial(ka::encode(retval)));
821  }
822 
823 private:
824  // Determination of the eval type.
825  template <typename U>
826  using e_type = decltype(math::pow(std::declval<const U &>(), std::declval<const T &>()));
827  template <typename U>
828  using eval_type = enable_if_t<conjunction<is_multipliable_in_place<e_type<U>>,
829  std::is_constructible<e_type<U>, int>, is_returnable<e_type<U>>>::value,
830  e_type<U>>;
831 
832 public:
834 
857  template <typename U>
858  eval_type<U> evaluate(const std::vector<U> &values, const symbol_fset &args) const
859  {
860  // NOTE: here we can check the values size only against args.
861  if (unlikely(values.size() != args.size())) {
863  std::invalid_argument,
864  "invalid vector of values for Kronecker monomial evaluation: the size of the vector of values ("
865  + std::to_string(values.size()) + ") differs from the size of the reference set of symbols ("
866  + std::to_string(args.size()) + ")");
867  }
868  if (args.size()) {
869  const auto v = unpack(args);
870  eval_type<U> retval(math::pow(values[0], v[0]));
871  for (decltype(v.size()) i = 1; i < v.size(); ++i) {
872  // NOTE: here maybe we could use mul3() and pow3() (to be implemented?).
873  // NOTE: math::pow() for C++ integrals produces an integer result, no need
874  // to worry about overflows.
875  retval *= math::pow(values[static_cast<decltype(values.size())>(i)], v[i]);
876  }
877  return retval;
878  }
879  return eval_type<U>(1);
880  }
881 
882 private:
883  // Subs type is same as eval_type.
884  template <typename U>
885  using subs_type = eval_type<U>;
886 
887 public:
889 
922  template <typename U>
923  std::vector<std::pair<subs_type<U>, kronecker_monomial>> subs(const symbol_idx_fmap<U> &smap,
924  const symbol_fset &args) const
925  {
926  if (unlikely(smap.size() && smap.rbegin()->first >= args.size())) {
927  // The last element of the substitution map must be a valid index into args.
929  std::invalid_argument,
930  "invalid argument(s) for substitution in a Kronecker monomial: the last index of the substitution map ("
931  + std::to_string(smap.rbegin()->first) + ") must be smaller than the monomial's size ("
932  + std::to_string(args.size()) + ")");
933  }
934  std::vector<std::pair<subs_type<U>, kronecker_monomial>> retval;
935  if (smap.size()) {
936  // The substitution map contains something, proceed to the substitution.
937  auto v = unpack(args);
938  // Init the return value from the exponentiation of the first value in the map.
939  auto it = smap.begin();
940  auto ret(math::pow(it->second, v[static_cast<decltype(v.size())>(it->first)]));
941  // Zero out the corresponding exponent.
942  v[static_cast<decltype(v.size())>(it->first)] = T(0);
943  // NOTE: move to the next element in the init statement of the for loop.
944  for (++it; it != smap.end(); ++it) {
945  ret *= math::pow(it->second, v[static_cast<decltype(v.size())>(it->first)]);
946  v[static_cast<decltype(v.size())>(it->first)] = T(0);
947  }
948  // NOTE: the is_returnable requirement ensures we can emplace back a pair
949  // containing the subs type.
950  retval.emplace_back(std::move(ret), kronecker_monomial(ka::encode(v)));
951  } else {
952  // Otherwise, the substitution yields 1 and the monomial is the original one.
953  retval.emplace_back(subs_type<U>(1), *this);
954  }
955  return retval;
956  }
957 
958 private:
959  // ipow subs utilities.
960  template <typename U>
961  using ips_type = decltype(math::pow(std::declval<const U &>(), std::declval<const integer &>()));
962  template <typename U>
963  using ipow_subs_type
964  = enable_if_t<conjunction<std::is_constructible<ips_type<U>, int>, is_returnable<ips_type<U>>>::value,
965  ips_type<U>>;
966 
967 public:
969 
1002  template <typename U>
1003  std::vector<std::pair<ipow_subs_type<U>, kronecker_monomial>> ipow_subs(const symbol_idx &p, const integer &n,
1004  const U &x, const symbol_fset &args) const
1005  {
1006  if (unlikely(!n.sgn())) {
1007  piranha_throw(std::invalid_argument,
1008  "invalid integral power for ipow_subs() in a Kronecker monomial: the power must be nonzero");
1009  }
1010  std::vector<std::pair<ipow_subs_type<U>, kronecker_monomial>> retval;
1011  if (p < args.size()) {
1012  PIRANHA_MAYBE_TLS integer q, r, d;
1013  auto v = unpack(args);
1014  d = v[static_cast<decltype(v.size())>(p)];
1015  // NOTE: regarding the sign of r: tdiv_qr() sets the sign of r to the sign of q.
1016  // The only two cases we are interested in here are where d and n have the same sign
1017  // (otherwise q will have negative sign and we never enter the 'if' below). With
1018  // d and n positive, everything is straightforward (r's sign will be positive).
1019  // If d and n are both negative, r will have negative sign, and it will satisfy:
1020  // q*n + r == d (with d < 0 and d < q*n)
1021  // This is the result we want: r is the number of steps towards -inf that q*n
1022  // must take to reach d.
1023  tdiv_qr(q, r, d, n);
1024  if (q.sgn() > 0) {
1025  v[static_cast<decltype(v.size())>(p)] = static_cast<T>(r);
1026  retval.emplace_back(math::pow(x, q), kronecker_monomial(ka::encode(v)));
1027  return retval;
1028  }
1029  }
1030  // Otherwise, the substitution yields 1 and the monomial is the original one.
1031  retval.emplace_back(ipow_subs_type<U>(1), *this);
1032  return retval;
1033  }
1035 
1054  void trim_identify(std::vector<char> &trim_mask, const symbol_fset &args) const
1055  {
1056  detail::km_trim_identify<v_type, ka>(trim_mask, args, m_value);
1057  }
1059 
1078  kronecker_monomial trim(const std::vector<char> &trim_mask, const symbol_fset &args) const
1079  {
1080  return kronecker_monomial(detail::km_trim<v_type, ka>(trim_mask, args, m_value));
1081  }
1083 
1089  bool operator<(const kronecker_monomial &other) const
1090  {
1091  return m_value < other.m_value;
1092  }
1093 
1094 #if defined(PIRANHA_WITH_MSGPACK)
1095 private:
1096  // Enablers for msgpack serialization.
1097  template <typename Stream>
1098  using msgpack_pack_enabler = enable_if_t<
1099  conjunction<is_msgpack_stream<Stream>, has_msgpack_pack<Stream, T>, has_msgpack_pack<Stream, v_type>>::value,
1100  int>;
1101  template <typename U>
1102  using msgpack_convert_enabler = enable_if_t<
1103  conjunction<has_msgpack_convert<typename U::value_type>, has_msgpack_convert<typename U::v_type>>::value, int>;
1104 
1105 public:
1107 
1121  template <typename Stream, msgpack_pack_enabler<Stream> = 0>
1122  void msgpack_pack(msgpack::packer<Stream> &packer, msgpack_format f, const symbol_fset &s) const
1123  {
1124  if (f == msgpack_format::binary) {
1125  piranha::msgpack_pack(packer, m_value, f);
1126  } else {
1127  auto tmp = unpack(s);
1128  piranha::msgpack_pack(packer, tmp, f);
1129  }
1130  }
1132 
1150  template <typename U = kronecker_monomial, msgpack_convert_enabler<U> = 0>
1151  void msgpack_convert(const msgpack::object &o, msgpack_format f, const symbol_fset &s)
1152  {
1153  if (f == msgpack_format::binary) {
1154  piranha::msgpack_convert(m_value, o, f);
1155  } else {
1156  v_type tmp;
1157  piranha::msgpack_convert(tmp, o, f);
1158  k_monomial_load_check_sizes(tmp.size(), s.size());
1159  *this = kronecker_monomial(tmp);
1160  }
1161  }
1162 #endif
1163 
1164 private:
1165  T m_value;
1166 };
1167 
1170 }
1171 
1172 // Implementation of the Boost s11n api.
1173 namespace boost
1174 {
1175 namespace serialization
1176 {
1177 
1178 template <typename Archive, typename T>
1179 inline void save(Archive &ar, const piranha::boost_s11n_key_wrapper<piranha::kronecker_monomial<T>> &k, unsigned)
1180 {
1181  if (std::is_same<Archive, boost::archive::binary_oarchive>::value) {
1182  piranha::boost_save(ar, k.key().get_int());
1183  } else {
1184  auto tmp = k.key().unpack(k.ss());
1185  piranha::boost_save(ar, tmp);
1186  }
1187 }
1188 
1189 template <typename Archive, typename T>
1190 inline void load(Archive &ar, piranha::boost_s11n_key_wrapper<piranha::kronecker_monomial<T>> &k, unsigned)
1191 {
1192  if (std::is_same<Archive, boost::archive::binary_iarchive>::value) {
1193  T value;
1194  piranha::boost_load(ar, value);
1195  k.key().set_int(value);
1196  } else {
1198  piranha::boost_load(ar, tmp);
1199  piranha::k_monomial_load_check_sizes(tmp.size(), k.ss().size());
1200  k.key() = piranha::kronecker_monomial<T>(tmp);
1201  }
1202 }
1203 
1204 template <typename Archive, typename T>
1205 inline void serialize(Archive &ar, piranha::boost_s11n_key_wrapper<piranha::kronecker_monomial<T>> &k, unsigned version)
1206 {
1207  split_free(ar, k, version);
1208 }
1209 }
1210 }
1211 
1212 namespace piranha
1213 {
1214 
1215 inline namespace impl
1216 {
1217 
1218 template <typename Archive, typename T>
1219 using k_monomial_boost_save_enabler = enable_if_t<
1220  conjunction<has_boost_save<Archive, T>, has_boost_save<Archive, typename kronecker_monomial<T>::v_type>>::value>;
1221 
1222 template <typename Archive, typename T>
1223 using k_monomial_boost_load_enabler = enable_if_t<
1224  conjunction<has_boost_load<Archive, T>, has_boost_load<Archive, typename kronecker_monomial<T>::v_type>>::value>;
1225 }
1226 
1228 
1238 template <typename Archive, typename T>
1240  k_monomial_boost_save_enabler<Archive, T>>
1241  : boost_save_via_boost_api<Archive, boost_s11n_key_wrapper<kronecker_monomial<T>>> {
1242 };
1243 
1245 
1255 template <typename Archive, typename T>
1257  k_monomial_boost_load_enabler<Archive, T>>
1258  : boost_load_via_boost_api<Archive, boost_s11n_key_wrapper<kronecker_monomial<T>>> {
1259 };
1260 }
1261 
1262 namespace std
1263 {
1264 
1266 template <typename T>
1267 struct hash<piranha::kronecker_monomial<T>> {
1269  using result_type = size_t;
1273 
1279  {
1280  return a.hash();
1281  }
1282 };
1283 }
1284 
1285 #endif
math_pow_t< T, U > pow(const T &x, const U &y)
Exponentiation.
Definition: pow.hpp:126
kronecker_monomial(const kronecker_monomial &other, const symbol_fset &)
Converting constructor.
Cf m_cf
Coefficient member.
Definition: term.hpp:189
static const limits_type & get_limits()
Get the limits of the Kronecker codification.
bool is_compatible(const symbol_fset &args) const noexcept
Compatibility check.
typename detail::static_vector_size_type< MaxSize >::type size_type
Size type.
kronecker_monomial()
Default constructor.
void boost_load(Archive &ar, T &x)
Load from Boost archive.
Definition: s11n.hpp:469
degree_type ldegree(const symbol_idx_fset &p, const symbol_fset &args) const
Partial low degree (equivalent to the partial degree).
Multiprecision integer class.
Definition: mp++.hpp:869
Default implementation of piranha::boost_load().
Definition: s11n.hpp:391
std::vector< std::pair< ipow_subs_type< U >, kronecker_monomial > > ipow_subs(const symbol_idx &p, const integer &n, const U &x, const symbol_fset &args) const
Substitution of integral power.
void msgpack_convert(T &x, const msgpack::object &o, msgpack_format f)
Convert msgpack object.
Definition: s11n.hpp:957
v_type unpack(const symbol_fset &args) const
Unpack internal integer instance.
kronecker_monomial(const T &n)
Constructor from T.
Key type concept check.
Definition: is_key.hpp:65
auto add3(T &a, const T &b, const T &c) -> decltype(add3_impl< T >()(a, b, c))
Ternary addition.
Definition: math.hpp:2582
static void multiply(std::array< term< Cf, kronecker_monomial >, multiply_arity > &res, const term< Cf, kronecker_monomial > &t1, const term< Cf, kronecker_monomial > &t2, const symbol_fset &)
Multiply terms with a Kronecker monomial key.
typename ka::size_type size_type
Size type.
void set_int(const T &n)
Set the internal integer instance.
Implementation of piranha::boost_load() via the Boost API.
Definition: s11n.hpp:363
kronecker_monomial(const symbol_fset &)
Constructor from set of symbols.
degree_type ldegree(const symbol_fset &args) const
Low degree (equivalent to the degree).
void msgpack_pack(msgpack::packer< Stream > &packer, msgpack_format f, const symbol_fset &s) const
Serialize in msgpack format.
Exceptions.
kronecker_monomial(Iterator begin, Iterator end, const symbol_fset &s)
Constructor from range and symbol set.
Default implementation of piranha::boost_save().
Definition: s11n.hpp:245
std::vector< std::pair< subs_type< U >, kronecker_monomial > > subs(const symbol_idx_fmap< U > &smap, const symbol_fset &args) const
Substitution.
void negate(T &x)
In-place negation.
Definition: math.hpp:329
std::pair< T, kronecker_monomial > partial(const symbol_idx &p, const symbol_fset &args) const
Partial derivative.
STL namespace.
Key m_key
Key member.
Definition: term.hpp:191
std::pair< bool, symbol_idx > is_linear(const symbol_fset &args) const
Detect linear monomial.
void print_tex(std::ostream &os, const symbol_fset &args) const
Print in TeX mode.
static const std::size_t multiply_arity
Arity of the multiply() method.
void print(std::ostream &os, const symbol_fset &args) const
Print.
T get_int() const
Get internal instance.
kronecker_monomial & operator=(const kronecker_monomial &other)=default
Copy assignment operator.
Detect the presence of piranha::msgpack_convert().
Definition: s11n.hpp:610
kronecker_monomial pow(const U &x, const symbol_fset &args) const
Exponentiation.
Kronecker monomial class.
std::size_t size_type
Size type.
std::size_t hash() const
Hash value.
void trim_identify(std::vector< char > &trim_mask, const symbol_fset &args) const
Identify symbols that can be trimmed.
Term class.
Definition: term.hpp:66
bool is_unitary(const symbol_fset &) const
Check if monomial is unitary.
#define piranha_throw(exception_type,...)
Exception-throwing macro.
Definition: exceptions.hpp:118
boost::container::flat_set< std::string > symbol_fset
Flat set of symbols.
result_type operator()(const argument_type &a) const
Hash operator.
Wrapper for the serialization of keys via Boost.
Definition: s11n.hpp:514
kronecker_monomial trim(const std::vector< char > &trim_mask, const symbol_fset &args) const
Trim.
msgpack_format
Serialization format for msgpack.
Definition: s11n.hpp:673
Detect if type can be returned from a function.
static int_type encode(const Vector &v)
Encode vector.
symbol_fset::size_type symbol_idx
Symbol index.
bool is_zero(const T &x)
Zero test.
Definition: math.hpp:133
Static vector class.
boost::container::flat_map< symbol_idx, T > symbol_idx_fmap
Flat map of symbol indices.
kronecker_monomial(const U &c)
Constructor from container.
Implementation of piranha::boost_save() via the Boost API.
Definition: s11n.hpp:217
bool operator==(const kronecker_monomial &other) const
Equality operator.
Root piranha namespace.
Definition: array_key.hpp:52
void msgpack_pack(msgpack::packer< Stream > &packer, const T &x, msgpack_format f)
Pack generic object in a msgpack stream.
Definition: s11n.hpp:856
void push_back(const value_type &x)
Copy-add element at the end of the vector.
Detect the presence of piranha::msgpack_pack().
Definition: s11n.hpp:607
bool operator!=(const kronecker_monomial &other) const
Inequality operator.
Type traits.
static_vector< T, 255u > v_type
Vector type used for temporary packing/unpacking.
Type trait to detect if a key type has a low degree property.
Definition: math.hpp:2072
void msgpack_convert(const msgpack::object &o, msgpack_format f, const symbol_fset &s)
Deserialize from msgpack object.
Type trait to detect differentiable keys.
Definition: math.hpp:1807
boost::container::flat_set< symbol_idx > symbol_idx_fset
Flat set of symbol indices.
Type trait to detect piranha::safe_cast().
Definition: safe_cast.hpp:237
Type trait to detect if a key type has a degree property.
Definition: math.hpp:2039
void boost_save(Archive &ar, const T &x)
Save to Boost archive.
Definition: s11n.hpp:328
std::pair< T, kronecker_monomial > integrate(const std::string &s, const symbol_fset &args) const
Integration.
kronecker_monomial(Iterator begin, Iterator end)
Constructor from range.
int sgn() const
Sign.
Definition: mp++.hpp:1611
#define PIRANHA_TT_CHECK(tt,...)
Macro for static type trait checks.
degree_type degree(const symbol_idx_fset &p, const symbol_fset &args) const
Partial degree.
kronecker_monomial merge_symbols(const symbol_idx_fmap< symbol_fset > &ins_map, const symbol_fset &args) const
Merge symbols.
eval_type< U > evaluate(const std::vector< U > &values, const symbol_fset &args) const
Evaluation.
bool operator<(const kronecker_monomial &other) const
Comparison operator.
kronecker_monomial(std::initializer_list< U > list)
Constructor from initializer list.
bool is_zero(const symbol_fset &) const noexcept
Zero check.
size_type size() const
Size.
safe_cast_type< To, From > safe_cast(const From &x)
Safe cast.
Definition: safe_cast.hpp:219
degree_type degree(const symbol_fset &args) const
Degree.