29 #ifndef PIRANHA_REAL_TRIGONOMETRIC_KRONECKER_MONOMIAL_HPP 30 #define PIRANHA_REAL_TRIGONOMETRIC_KRONECKER_MONOMIAL_HPP 40 #include <initializer_list> 46 #include <type_traits> 47 #include <unordered_map> 51 #include <piranha/binomial.hpp> 52 #include <piranha/config.hpp> 53 #include <piranha/detail/cf_mult_impl.hpp> 54 #include <piranha/detail/km_commons.hpp> 55 #include <piranha/detail/prepare_for_print.hpp> 56 #include <piranha/detail/safe_integral_adder.hpp> 58 #include <piranha/is_cf.hpp> 59 #include <piranha/is_key.hpp> 60 #include <piranha/kronecker_array.hpp> 61 #include <piranha/math.hpp> 62 #include <piranha/mp_integer.hpp> 63 #include <piranha/s11n.hpp> 64 #include <piranha/safe_cast.hpp> 65 #include <piranha/static_vector.hpp> 66 #include <piranha/symbol_utils.hpp> 67 #include <piranha/term.hpp> 118 template <typename T = std::make_signed<std::size_t>::type>
158 template <
typename U>
159 using init_list_enabler = enable_if_t<has_safe_cast<value_type, U>::value,
int>;
180 template <
typename U, init_list_enabler<U> = 0>
188 template <
typename Iterator>
189 using it_ctor_enabler
190 = enable_if_t<conjunction<is_input_iterator<Iterator>,
214 template <
typename Iterator, it_ctor_enabler<Iterator> = 0>
216 : m_value(0), m_flavour(flavour)
220 start, end, std::back_inserter(tmp),
221 [](
const typename std::iterator_traits<Iterator>::value_type &v) {
return safe_cast<
value_type>(v); });
309 static bool canonicalise_impl(
v_type &unpacked)
311 const auto size = unpacked.size();
312 bool sign_change =
false;
313 for (decltype(unpacked.size()) i = 0u; i < size; ++i) {
314 if (sign_change || unpacked[i] <
value_type(0)) {
315 unpacked[i] =
static_cast<value_type>(-unpacked[i]);
342 auto unpacked =
unpack(args);
343 const bool retval = canonicalise_impl(unpacked);
367 const auto s = args.size();
374 if (s >= limits.size()) {
377 const auto &l = limits[s];
379 if (m_value < std::get<1u>(l) || m_value > std::get<2u>(l)) {
385 const auto unpacked =
unpack(args);
387 piranha_assert(unpacked.size() > 0u);
405 return m_value ==
value_type(0) && !m_flavour;
446 return (!m_value && m_flavour);
451 using degree_type = add_t<T, T>;
468 const auto tmp =
unpack(args);
470 piranha_assert(tmp.size() == args.size());
471 degree_type retval(0);
472 for (
const auto &x : tmp) {
473 detail::safe_integral_adder(retval, static_cast<degree_type>(x));
507 const auto tmp =
unpack(args);
508 piranha_assert(tmp.size() == args.size());
509 if (unlikely(p.size() && *p.rbegin() >= tmp.size())) {
511 "the largest value in the positions set for the computation of the " 512 "partial trigonometric degree of a real trigonometric Kronecker monomial is " 513 + std::to_string(*p.rbegin()) +
", but the monomial has a size of only " 514 + std::to_string(tmp.size()));
516 degree_type retval(0);
518 detail::safe_integral_adder(retval, static_cast<degree_type>(tmp[
static_cast<decltype(tmp.size())
>(idx)]));
538 using order_type = decltype(
math::abs(std::declval<const T &>()) +
math::abs(std::declval<const T &>()));
555 const auto tmp =
unpack(args);
556 piranha_assert(tmp.size() == args.size());
557 order_type retval(0);
558 for (
const auto &x : tmp) {
561 detail::safe_integral_adder(retval, static_cast<order_type>(
math::abs(x)));
595 const auto tmp =
unpack(args);
596 piranha_assert(tmp.size() == args.size());
597 if (unlikely(p.size() && *p.rbegin() >= tmp.size())) {
599 "the largest value in the positions set for the computation of the " 600 "partial trigonometric order of a real trigonometric Kronecker monomial is " 601 + std::to_string(*p.rbegin()) +
", but the monomial has a size of only " 602 + std::to_string(tmp.size()));
604 order_type retval(0);
606 detail::safe_integral_adder(
607 retval, static_cast<degree_type>(
math::abs(tmp[
static_cast<decltype(tmp.size())
>(idx)])));
627 template <
typename Cf>
628 using multiply_enabler = enable_if_t<
660 template <
typename Cf, multiply_enabler<Cf> = 0>
666 cf_mult_impl(res[0u].m_cf, t1.
m_cf, t2.
m_cf);
667 res[1u].m_cf = res[0u].m_cf;
668 const bool f1 = t1.
m_key.get_flavour(), f2 = t2.
m_key.get_flavour();
671 }
else if (!f1 && !f2) {
674 }
else if (!f1 && f2) {
681 auto &retval_plus = res[0u].m_key;
682 auto &retval_minus = res[1u].m_key;
684 bool sign_plus =
false, sign_minus =
false;
685 const auto size = args.size();
686 const auto tmp1 = t1.
m_key.unpack(args), tmp2 = t2.
m_key.unpack(args);
687 v_type result_plus, result_minus;
690 detail::safe_integral_adder(result_plus[i], tmp2[i]);
696 detail::safe_integral_adder(result_minus[i], static_cast<value_type>(-tmp2[i]));
699 sign_plus = canonicalise_impl(result_plus);
700 sign_minus = canonicalise_impl(result_minus);
703 retval_plus.m_value = re_plus;
704 retval_minus.m_value = re_minus;
705 const bool f = (t1.
m_key.get_flavour() == t2.
m_key.get_flavour());
706 retval_plus.m_flavour = f;
707 retval_minus.m_flavour = f;
709 if (sign_plus && !res[0u].m_key.get_flavour()) {
712 if (sign_minus && !res[1u].m_key.get_flavour()) {
722 return static_cast<std::size_t
>(m_value);
733 return (m_value == other.m_value && m_flavour == other.m_flavour);
743 return (m_value != other.m_value || m_flavour != other.m_flavour);
760 return detail::km_unpack<v_type, ka>(args, m_value);
782 const auto tmp =
unpack(args);
783 piranha_assert(tmp.size() == args.size());
785 bool empty_output =
true;
786 auto it_args = args.begin();
787 for (decltype(tmp.size()) i = 0u; i < tmp.size(); ++i, ++it_args) {
788 if (tmp[i] != zero) {
791 if (tmp[i] > zero && !empty_output) {
795 if (tmp[i] == m_one) {
797 }
else if (tmp[i] != one) {
798 os << detail::prepare_for_print(tmp[i]) <<
'*';
802 empty_output =
false;
823 os <<
"\\cos{\\left(";
825 os <<
"\\sin{\\left(";
827 const auto tmp =
unpack(args);
828 piranha_assert(tmp.size() == args.size());
830 bool empty_output =
true;
831 auto it_args = args.begin();
832 for (decltype(tmp.size()) i = 0u; i < tmp.size(); ++i, ++it_args) {
833 if (tmp[i] != zero) {
836 if (tmp[i] > zero && !empty_output) {
840 if (tmp[i] == m_one) {
842 }
else if (tmp[i] != one) {
843 os << static_cast<long long>(tmp[i]);
846 os <<
'{' << *it_args <<
'}';
847 empty_output =
false;
871 if (p >= args.size() || v[
static_cast<decltype(v.size())
>(p)] == T(0)) {
876 const auto v_b = v.begin();
900 std::pair<T, real_trigonometric_kronecker_monomial>
integrate(
const std::string &s,
const symbol_fset &args)
const 903 auto it_args = args.begin();
911 return std::make_pair(static_cast<value_type>(-v[i]),
925 template <
typename U>
926 using eval_t_cos = decltype(
math::cos(std::declval<
const mul_t<T, U> &>()));
927 template <
typename U>
928 using eval_t_sin = decltype(
math::sin(std::declval<
const mul_t<T, U> &>()));
930 template <
typename U>
932 = enable_if_t<conjunction<
934 std::is_same<eval_t_cos<U>, eval_t_sin<U>>,
936 std::is_constructible<eval_t_cos<U>,
const int &>,
942 std::is_constructible<mul_t<T, U>,
const int &>,
944 std::is_move_constructible<mul_t<T, U>>, std::is_destructible<mul_t<T, U>>>::value,
965 template <
typename U>
969 if (unlikely(values.size() != args.size())) {
970 piranha_throw(std::invalid_argument,
"invalid vector of values for real trigonometric Kronecker monomial " 971 "evaluation: the size of the vector of values (" 972 + std::to_string(values.size())
973 +
") differs from the size of the reference set of symbols (" 974 + std::to_string(args.size()) +
")");
977 const auto v =
unpack(args);
981 return eval_type<U>(1);
983 return eval_type<U>(0);
987 auto tmp(v[0] * values[0]);
989 for (decltype(values.size()) i = 1; i < values.size(); ++i) {
991 tmp += v[
static_cast<decltype(v.size())
>(i)] * values[i];
1003 template <
typename U>
1004 using subs_type = enable_if_t<has_negate<eval_type<U>>::value, eval_type<U>>;
1049 template <
typename U>
1053 if (unlikely(smap.size() && smap.rbegin()->first >= args.size())) {
1055 piranha_throw(std::invalid_argument,
"invalid argument(s) for substitution in a real trigonometric " 1056 "Kronecker monomial: the last index of the substitution map (" 1057 + std::to_string(smap.rbegin()->first)
1058 +
") must be smaller than the monomial's size (" 1059 + std::to_string(args.size()) +
")");
1069 auto it = smap.begin();
1070 auto tmp(v[
static_cast<decltype(v.size())
>(it->first)] * it->second);
1072 v[
static_cast<decltype(v.size())
>(it->first)] = T(0);
1076 for (++it; it != smap.end(); ++it) {
1078 tmp += v[
static_cast<decltype(v.size())
>(it->first)] * it->second;
1079 v[static_cast<decltype(v.size())>(it->first)] = T(0);
1083 const bool sign_changed = canonicalise_impl(v);
1091 if (!sign_changed) {
1112 retval.emplace_back(subs_type<U>(1), *
this);
1117 retval.emplace_back(subs_type<U>(1), *
this);
1125 template <
typename U>
1126 using t_subs_t = decltype(std::declval<const integer &>() * std::declval<
const mul_t<U, U> &>());
1127 template <
typename U>
1128 using t_subs_type = enable_if_t<
1129 conjunction<std::is_default_constructible<U>, std::is_constructible<U, const int &>, std::is_move_assignable<U>,
1130 std::is_destructible<U>, std::is_assignable<U &, mul_t<U, U> &&>, std::is_destructible<mul_t<U, U>>,
1131 std::is_move_constructible<t_subs_t<U>>, std::is_destructible<t_subs_t<U>>,
1133 std::is_move_constructible<mul_t<U, U>>>::value,
1173 template <
typename U>
1179 if (idx < args.size()) {
1182 std::swap(n, v[
static_cast<decltype(v.size())
>(idx)]);
1184 const auto abs_n =
static_cast<T
>(std::abs(n));
1187 std::unordered_map<T, U> c_map, s_map;
1191 for (T k = 0; k < abs_n; ++k) {
1193 c_map[
static_cast<T
>(k + 1)] = c_map[k] * c;
1194 s_map[
static_cast<T
>(k + 1)] = s_map[k] * s;
1201 t_subs_type<U> cos_nx(cos_phase(abs_n) *
math::binomial(
integer(abs_n), T(0)) * (c_map[T(0)] * s_map[abs_n])),
1204 for (T k = 0; k < abs_n; ++k) {
1205 const auto p =
static_cast<T
>(abs_n - (k + 1));
1206 piranha_assert(p >= T(0));
1208 const auto tmp = c_map[
static_cast<T
>(k + 1)] * s_map[p];
1211 cos_nx += cos_phase(p) * tmp_bin * tmp;
1212 sin_nx += sin_phase(p) * tmp_bin * tmp;
1220 const bool sign_changed = canonicalise_impl(v);
1230 if (!sign_changed) {
1265 detail::km_trim_identify<v_type, ka>(trim_mask, args, m_value);
1302 if (m_value == other.m_value) {
1303 return m_flavour < other.m_flavour;
1305 return m_value < other.m_value;
1308 #if defined(PIRANHA_WITH_MSGPACK) 1310 template <
typename Stream>
1311 using msgpack_pack_enabler
1315 template <
typename U>
1316 using msgpack_convert_enabler
1338 template <
typename Stream, msgpack_pack_enabler<Stream> = 0>
1341 packer.pack_array(2);
1371 template <
typename U = real_trigonometric_kronecker_monomial, msgpack_convert_enabler<U> = 0>
1374 std::array<msgpack::object, 2> tmp;
1382 if (unlikely(tmp_v.
size() != s.size())) {
1384 "incompatible symbol set in trigonometric monomial serialization: the reference " 1385 "symbol set has a size of " 1386 + std::to_string(s.size())
1387 +
", while the trigonometric monomial being deserialized has a size of " 1388 + std::to_string(tmp_v.
size()));
1401 template <
typename T>
1411 namespace serialization
1414 template <
typename Archive,
typename T>
1415 inline void save(Archive &ar,
1418 if (std::is_same<Archive, boost::archive::binary_oarchive>::value) {
1421 auto tmp = k.key().unpack(k.ss());
1427 template <
typename Archive,
typename T>
1431 if (std::is_same<Archive, boost::archive::binary_iarchive>::value) {
1434 k.key().set_int(value);
1438 if (unlikely(tmp.
size() != k.ss().size())) {
1439 piranha_throw(std::invalid_argument,
"invalid size detected in the deserialization of a real Kronercker " 1440 "trigonometric monomial: the deserialized size is " 1441 + std::to_string(tmp.
size())
1442 +
" but the reference symbol set has a size of " 1443 + std::to_string(k.ss().size()));
1453 k.key().set_flavour(f);
1456 template <
typename Archive,
typename T>
1457 inline void serialize(Archive &ar,
1461 split_free(ar, k, version);
1469 inline namespace impl
1472 template <
typename Archive,
typename T>
1473 using rtk_monomial_boost_save_enabler = enable_if_t<
1474 conjunction<has_boost_save<Archive, T>, has_boost_save<Archive, bool>,
1475 has_boost_save<Archive, typename real_trigonometric_kronecker_monomial<T>::v_type>>::value>;
1477 template <
typename Archive,
typename T>
1478 using rtk_monomial_boost_load_enabler = enable_if_t<
1479 conjunction<has_boost_load<Archive, T>, has_boost_load<Archive, bool>,
1480 has_boost_load<Archive, typename real_trigonometric_kronecker_monomial<T>::v_type>>::value>;
1495 template <
typename Archive,
typename T>
1497 rtk_monomial_boost_save_enabler<Archive, T>>
1514 template <
typename Archive,
typename T>
1516 rtk_monomial_boost_load_enabler<Archive, T>>
1525 template <
typename T>
1526 struct hash<
piranha::real_trigonometric_kronecker_monomial<T>> {
bool operator==(const real_trigonometric_kronecker_monomial &other) const
Equality operator.
Cf m_cf
Coefficient member.
real_trigonometric_kronecker_monomial()
Default constructor.
void print(std::ostream &os, const symbol_fset &args) const
Print.
static const limits_type & get_limits()
Get the limits of the Kronecker codification.
std::size_t hash() const
Hash value.
typename detail::static_vector_size_type< MaxSize >::type size_type
Size type.
real_trigonometric_kronecker_monomial & operator=(const real_trigonometric_kronecker_monomial &other)=default
Copy assignment operator.
iterator begin()
Begin iterator.
void boost_load(Archive &ar, T &x)
Load from Boost archive.
value_type get_int() const
Get internal instance.
Default implementation of piranha::boost_load().
mp_integer< 1 > integer
Alias for piranha::mp_integer with 1 limb of static storage.
void msgpack_convert(T &x, const msgpack::object &o, msgpack_format f)
Convert msgpack object.
bool is_zero(const symbol_fset &) const noexcept
Zero check.
eval_type< U > evaluate(const std::vector< U > &values, const symbol_fset &args) const
Evaluation.
degree_type t_ldegree(const symbol_fset &args) const
Low trigonometric degree (equivalent to the trigonometric degree).
ka::size_type size_type
Size type.
real_trigonometric_kronecker_monomial(const Iterator &start, const Iterator &end, bool flavour=true)
Constructor from range.
Implementation of piranha::boost_load() via the Boost API.
degree_type t_degree(const symbol_fset &args) const
Trigonometric degree.
order_type t_lorder(const symbol_idx_fset &p, const symbol_fset &args) const
Partial low trigonometric order (equivalent to the partial trigonometric order).
Type trait to detect if a key type has a trigonometric degree property.
In-place addable type trait.
detail::math_cos_type< T > cos(const T &x)
Cosine.
Default implementation of piranha::boost_save().
void negate(T &x)
In-place negation.
Type trait to detect the presence of the piranha::math::negate function.
static const std::size_t multiply_arity
Arity of the multiply() method.
~real_trigonometric_kronecker_monomial()
Trivial destructor.
static const size_type max_size
Maximum monomial size.
Detect the presence of piranha::msgpack_convert().
bool canonicalise(const symbol_fset &args)
Canonicalise.
static void multiply(std::array< term< Cf, real_trigonometric_kronecker_monomial >, multiply_arity > &res, const term< Cf, real_trigonometric_kronecker_monomial > &t1, const term< Cf, real_trigonometric_kronecker_monomial > &t2, const symbol_fset &args)
Multiply terms with a trigonometric monomial.
void trim_identify(std::vector< char > &trim_mask, const symbol_fset &args) const
Identify symbols that can be trimmed.
std::size_t size_type
Size type.
void msgpack_pack(msgpack::packer< Stream > &packer, msgpack_format f, const symbol_fset &s) const
Serialize in msgpack format.
v_type unpack(const symbol_fset &args) const
Unpack internal integer instance.
typename detail::min_int_impl< T, Args... >::type min_int
Detect narrowest integer type.
void set_flavour(bool f)
Set flavour.
std::vector< std::pair< t_subs_type< U >, real_trigonometric_kronecker_monomial > > t_subs(const symbol_idx &idx, const U &c, const U &s, const symbol_fset &args) const
Trigonometric substitution.
#define piranha_throw(exception_type,...)
Exception-throwing macro.
boost::container::flat_set< std::string > symbol_fset
Flat set of symbols.
iterator end()
End iterator.
degree_type t_degree(const symbol_idx_fset &p, const symbol_fset &args) const
Partial trigonometric degree.
void set_int(const value_type &n)
Set the internal integer instance.
Wrapper for the serialization of keys via Boost.
msgpack_format
Serialization format for msgpack.
void print_tex(std::ostream &os, const symbol_fset &args) const
Print in TeX mode.
Detect if type can be returned from a function.
auto abs(const T &x) -> decltype(abs_impl< T >()(x))
Absolute value.
static int_type encode(const Vector &v)
Encode vector.
Type trait to detect if a key type has a trigonometric order property.
real_trigonometric_kronecker_monomial trim(const std::vector< char > &trim_mask, const symbol_fset &args) const
Trim.
symbol_fset::size_type symbol_idx
Symbol index.
bool operator!=(const real_trigonometric_kronecker_monomial &other) const
Inequality operator.
Type trait to detect if a key type has a trigonometric low order property.
result_type operator()(const argument_type &a) const
Hash operator.
Real trigonometric Kronecker monomial class.
boost::container::flat_map< symbol_idx, T > symbol_idx_fmap
Flat map of symbol indices.
Implementation of piranha::boost_save() via the Boost API.
math_binomial_type< T, U > binomial(const T &x, const U &y)
Generalised binomial coefficient.
real_trigonometric_kronecker_monomial(std::initializer_list< U > list, bool flavour=true)
Constructor from initalizer list.
order_type t_order(const symbol_fset &args) const
Trigonometric order.
void msgpack_pack(msgpack::packer< Stream > &packer, const T &x, msgpack_format f)
Pack generic object in a msgpack stream.
std::vector< std::pair< subs_type< U >, real_trigonometric_kronecker_monomial > > subs(const symbol_idx_fmap< U > &smap, const symbol_fset &args) const
Substitution.
std::pair< T, real_trigonometric_kronecker_monomial > partial(const symbol_idx &p, const symbol_fset &args) const
Partial derivative.
void push_back(const value_type &x)
Copy-add element at the end of the vector.
Detect the presence of piranha::msgpack_pack().
real_trigonometric_kronecker_monomial(const value_type &n, bool f)
Constructor from value_type and flavour.
order_type t_order(const symbol_idx_fset &p, const symbol_fset &args) const
Partial trigonometric order.
real_trigonometric_kronecker_monomial(const real_trigonometric_kronecker_monomial &other, const symbol_fset &)
Converting constructor.
bool is_unitary(const symbol_fset &) const
Check if monomial is unitary.
static_vector< value_type, max_size > v_type
Vector type used for temporary packing/unpacking.
real_trigonometric_kronecker_monomial merge_symbols(const symbol_idx_fmap< symbol_fset > &ins_map, const symbol_fset &args) const
Merge symbols.
void msgpack_convert(const msgpack::object &o, msgpack_format f, const symbol_fset &s)
Deserialize from msgpack object.
Type trait to detect differentiable keys.
size_t result_type
Result type.
bool is_compatible(const symbol_fset &args) const noexcept
Compatibility check.
boost::container::flat_set< symbol_idx > symbol_idx_fset
Flat set of symbol indices.
real_trigonometric_kronecker_monomial(const symbol_fset &)
Constructor from set of symbols.
Type trait to detect piranha::safe_cast().
order_type t_lorder(const symbol_fset &args) const
Low trigonometric order (equivalent to the trigonometric order).
void boost_save(Archive &ar, const T &x)
Save to Boost archive.
Detect piranha::math::mul3().
Type trait to detect if a key type has a trigonometric low degree property.
piranha::real_trigonometric_kronecker_monomial< T > argument_type
Argument type.
#define PIRANHA_TT_CHECK(tt,...)
Macro for static type trait checks.
degree_type t_ldegree(const symbol_idx_fset &p, const symbol_fset &args) const
Partial low trigonometric degree (equivalent to the partial trigonometric degree).
std::pair< T, real_trigonometric_kronecker_monomial > integrate(const std::string &s, const symbol_fset &args) const
Integration.
bool get_flavour() const
Get flavour.
bool operator<(const real_trigonometric_kronecker_monomial &other) const
Comparison operator.
detail::math_sin_type< T > sin(const T &x)
Sine.
size_type size() const
Size.
safe_cast_type< To, From > safe_cast(const From &x)
Safe cast.