29 #ifndef PIRANHA_KRONECKER_MONOMIAL_HPP 30 #define PIRANHA_KRONECKER_MONOMIAL_HPP 37 #include <initializer_list> 44 #include <type_traits> 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> 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> 77 template <
typename T,
typename U>
78 inline void k_monomial_load_check_sizes(T s1, U s2)
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 (" 87 +
") differs from the size of the reference symbol set (" 88 + std::to_string(s2) +
")");
118 template <typename T = std::make_signed<std::size_t>::type>
155 template <
typename U>
156 using container_ctor_enabler
157 = enable_if_t<conjunction<has_input_begin_end<const U>,
159 std::begin(std::declval<const U &>()))>
::value_type>>::value,
162 template <
typename Iterator>
166 std::transform(begin, end, std::back_inserter(tmp),
167 [](
const uncvref_t<decltype(*begin)> &v) {
return safe_cast<T>(v); });
187 template <
typename U, container_ctor_enabler<U> = 0>
193 template <
typename U>
194 using init_list_ctor_enabler = container_ctor_enabler<std::initializer_list<U>>;
206 template <
typename U, init_list_ctor_enabler<U> = 0>
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,
238 template <
typename Iterator, it_ctor_enabler<Iterator> = 0>
241 construct_from_range(begin, end);
260 template <
typename Iterator, it_ctor_enabler<Iterator> = 0>
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()) +
")");
351 const auto s = args.size();
358 if (s >= limits.size()) {
361 const auto &l = limits[
static_cast<decltype(limits.size())
>(s)];
363 return (m_value >= std::get<1u>(l) && m_value <= std::get<2u>(l));
403 return kronecker_monomial(detail::km_merge_symbols<v_type, ka>(ins_map, args, m_value));
417 using degree_type = add_t<T, T>;
434 const auto tmp =
unpack(args);
436 piranha_assert(tmp.size() == args.size());
437 degree_type retval(0);
438 for (
const auto &x : tmp) {
441 detail::safe_integral_adder(retval, static_cast<degree_type>(x));
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()));
484 degree_type retval(0);
486 detail::safe_integral_adder(retval, static_cast<degree_type>(tmp[
static_cast<decltype(tmp.size())
>(idx)]));
506 template <
typename Cf>
507 using multiply_enabler = enable_if_t<has_mul3<Cf>::value,
int>;
529 template <
typename Cf, multiply_enabler<Cf> = 0>
535 cf_mult_impl(res[0u].m_cf, t1.
m_cf, t2.
m_cf);
545 return static_cast<std::size_t
>(m_value);
556 return m_value == other.m_value;
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) {
596 if (n_linear != 1u) {
599 return std::make_pair(
true,
symbol_idx{candidate});
604 template <
typename U>
605 using pow_enabler = monomial_pow_enabler<T, U>;
634 template <
typename U, pow_enabler<U> = 0>
639 monomial_pow_mult_exp(n, n, x, monomial_pow_dispatcher<T, U>{});
658 return detail::km_unpack<v_type, ka>(args, m_value);
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)) {
681 empty_output =
false;
682 if (tmp[i] != T(1)) {
683 os <<
"**" << detail::prepare_for_print(tmp[i]);
699 const auto tmp =
unpack(args);
700 std::ostringstream oss_num, oss_den, *cur_oss;
702 auto it_args = args.begin();
703 for (decltype(tmp.size()) i = 0u; i < tmp.size(); ++i, ++it_args) {
705 if (cur_value != T(0)) {
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) <<
"}";
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()) {
719 }
else if (num_str.empty() && !den_str.empty()) {
720 os <<
"\\frac{1}{" << den_str <<
"}";
743 if (p >= args.size() || v[
static_cast<decltype(v.size())
>(p)] == T(0)) {
748 auto v_b = v.begin();
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");
757 v_b[p] =
static_cast<T
>(n - T(1));
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) {
799 if (unlikely(retval[i] == std::numeric_limits<T>::max())) {
802 "positive overflow error in the calculation of the antiderivative of a Kronecker monomial");
805 retval[i] =
static_cast<T
>(retval[i] + T(1));
808 "unable to perform Kronecker monomial integration: a negative " 809 "unitary exponent was encountered in correspondence of the variable '" 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>>,
857 template <
typename U>
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()) +
")");
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) {
875 retval *=
math::pow(values[
static_cast<decltype(values.size())
>(i)], v[i]);
879 return eval_type<U>(1);
884 template <
typename U>
885 using subs_type = eval_type<U>;
922 template <
typename U>
926 if (unlikely(smap.size() && smap.rbegin()->first >= args.size())) {
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()) +
")");
939 auto it = smap.begin();
940 auto ret(
math::pow(it->second, v[static_cast<decltype(v.size())>(it->first)]));
942 v[
static_cast<decltype(v.size())
>(it->first)] = T(0);
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);
953 retval.emplace_back(subs_type<U>(1), *
this);
960 template <
typename U>
961 using ips_type = decltype(
math::pow(std::declval<const U &>(), std::declval<const integer &>()));
962 template <
typename U>
1002 template <
typename U>
1006 if (unlikely(!n.
sgn())) {
1008 "invalid integral power for ipow_subs() in a Kronecker monomial: the power must be nonzero");
1011 if (p < args.size()) {
1012 PIRANHA_MAYBE_TLS
integer q, r, d;
1014 d = v[
static_cast<decltype(v.size())
>(p)];
1023 tdiv_qr(q, r, d, n);
1025 v[
static_cast<decltype(v.size())
>(p)] = static_cast<T>(r);
1031 retval.emplace_back(ipow_subs_type<U>(1), *
this);
1056 detail::km_trim_identify<v_type, ka>(trim_mask, args, m_value);
1091 return m_value < other.m_value;
1094 #if defined(PIRANHA_WITH_MSGPACK) 1097 template <
typename Stream>
1098 using msgpack_pack_enabler = enable_if_t<
1101 template <
typename U>
1102 using msgpack_convert_enabler = enable_if_t<
1121 template <
typename Stream, msgpack_pack_enabler<Stream> = 0>
1150 template <
typename U = kronecker_monomial, msgpack_convert_enabler<U> = 0>
1158 k_monomial_load_check_sizes(tmp.
size(), s.size());
1175 namespace serialization
1178 template <
typename Archive,
typename T>
1181 if (std::is_same<Archive, boost::archive::binary_oarchive>::value) {
1184 auto tmp = k.key().unpack(k.ss());
1189 template <
typename Archive,
typename T>
1192 if (std::is_same<Archive, boost::archive::binary_iarchive>::value) {
1195 k.key().set_int(value);
1199 piranha::k_monomial_load_check_sizes(tmp.
size(), k.ss().size());
1204 template <
typename Archive,
typename T>
1207 split_free(ar, k, version);
1215 inline namespace impl
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>;
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>;
1238 template <
typename Archive,
typename T>
1240 k_monomial_boost_save_enabler<Archive, T>>
1255 template <
typename Archive,
typename T>
1257 k_monomial_boost_load_enabler<Archive, T>>
1266 template <
typename T>
math_pow_t< T, U > pow(const T &x, const U &y)
Exponentiation.
kronecker_monomial(const kronecker_monomial &other, const symbol_fset &)
Converting constructor.
Cf m_cf
Coefficient member.
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.
degree_type ldegree(const symbol_idx_fset &p, const symbol_fset &args) const
Partial low degree (equivalent to the partial degree).
Multiprecision integer class.
Default implementation of piranha::boost_load().
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.
v_type unpack(const symbol_fset &args) const
Unpack internal integer instance.
kronecker_monomial(const T &n)
Constructor from T.
auto add3(T &a, const T &b, const T &c) -> decltype(add3_impl< T >()(a, b, c))
Ternary addition.
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.
size_t result_type
Result type.
void set_int(const T &n)
Set the internal integer instance.
Implementation of piranha::boost_load() via the Boost API.
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.
kronecker_monomial(Iterator begin, Iterator end, const symbol_fset &s)
Constructor from range and symbol set.
Default implementation of piranha::boost_save().
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.
std::pair< T, kronecker_monomial > partial(const symbol_idx &p, const symbol_fset &args) const
Partial derivative.
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().
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.
bool is_unitary(const symbol_fset &) const
Check if monomial is unitary.
#define piranha_throw(exception_type,...)
Exception-throwing macro.
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.
kronecker_monomial trim(const std::vector< char > &trim_mask, const symbol_fset &args) const
Trim.
msgpack_format
Serialization format for msgpack.
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.
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.
bool operator==(const kronecker_monomial &other) const
Equality operator.
void msgpack_pack(msgpack::packer< Stream > &packer, const T &x, msgpack_format f)
Pack generic object in a msgpack stream.
void push_back(const value_type &x)
Copy-add element at the end of the vector.
Detect the presence of piranha::msgpack_pack().
bool operator!=(const kronecker_monomial &other) const
Inequality operator.
~kronecker_monomial()
Destructor.
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.
void msgpack_convert(const msgpack::object &o, msgpack_format f, const symbol_fset &s)
Deserialize from msgpack object.
Type trait to detect differentiable keys.
boost::container::flat_set< symbol_idx > symbol_idx_fset
Flat set of symbol indices.
Type trait to detect piranha::safe_cast().
Type trait to detect if a key type has a degree property.
void boost_save(Archive &ar, const T &x)
Save to Boost archive.
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.
#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.
degree_type degree(const symbol_fset &args) const
Degree.