29 #ifndef PIRANHA_SERIES_HPP 30 #define PIRANHA_SERIES_HPP 34 #include <boost/iostreams/copy.hpp> 35 #include <boost/iostreams/filter/bzip2.hpp> 36 #include <boost/iostreams/filtering_streambuf.hpp> 37 #include <boost/iterator/indirect_iterator.hpp> 38 #include <boost/iterator/transform_iterator.hpp> 39 #include <boost/numeric/conversion/cast.hpp> 55 #include <type_traits> 56 #include <unordered_map> 60 #include <piranha/config.hpp> 61 #include <piranha/convert_to.hpp> 62 #include <piranha/debug_access.hpp> 63 #include <piranha/detail/init_data.hpp> 64 #include <piranha/detail/series_fwd.hpp> 65 #include <piranha/detail/sfinae_types.hpp> 67 #include <piranha/hash_set.hpp> 68 #include <piranha/invert.hpp> 69 #include <piranha/is_cf.hpp> 70 #include <piranha/key_is_convertible.hpp> 71 #include <piranha/math.hpp> 72 #include <piranha/mp_integer.hpp> 73 #include <piranha/pow.hpp> 74 #include <piranha/print_coefficient.hpp> 75 #include <piranha/print_tex_coefficient.hpp> 76 #include <piranha/s11n.hpp> 77 #include <piranha/safe_cast.hpp> 78 #include <piranha/series_multiplier.hpp> 79 #include <piranha/settings.hpp> 80 #include <piranha/symbol_utils.hpp> 81 #include <piranha/term.hpp> 91 template <
typename S1,
typename S2,
typename F>
92 auto series_merge_f(S1 &&s1, S2 &&s2,
const F &f) -> decltype(f(std::forward<S1>(s1), std::forward<S2>(s2)));
101 template <
typename Term,
typename Derived>
102 inline std::pair<typename Term::cf_type, Derived> pair_from_term(
const symbol_fset &s,
const Term &t)
104 typedef typename Term::cf_type cf_type;
106 retval.set_symbol_set(s);
107 retval.insert(Term(cf_type(1), t.m_key));
108 return std::make_pair(t.m_cf, std::move(retval));
113 template <
typename Functor,
typename RetT,
typename T>
114 inline RetT apply_cf_functor(
const T &s)
116 using term_type =
typename RetT::term_type;
117 using cf_type =
typename term_type::cf_type;
118 using key_type =
typename term_type::key_type;
119 if (!s.is_single_coefficient()) {
121 std::string(
"cannot compute ") + Functor::name +
", series is not single-coefficient");
126 retval.insert(term_type(f(cf_type(0)), key_type(
symbol_fset{})));
128 retval.insert(term_type(f(s._container().begin()->m_cf), key_type(
symbol_fset{})));
141 template <
typename T>
144 static const bool implementation_defined
145 = conjunction<std::is_base_of<detail::series_tag, T>, is_container_element<T>>
::value;
149 static const bool value = implementation_defined;
152 template <
typename T>
156 inline namespace impl
159 template <
typename T,
typename Cf>
160 using series_rebind_t =
typename uncvref_t<T>::template rebind<uncvref_t<Cf>>;
162 template <
typename T,
typename Cf>
163 using series_rebind_cf_t =
typename series_rebind_t<T, Cf>::term_type::cf_type;
165 template <
typename T,
typename Cf,
typename =
void>
166 struct series_is_rebindable_impl {
167 static const bool value = conjunction<is_series<detected_t<series_rebind_t, T, Cf>>,
168 std::is_same<detected_t<series_rebind_cf_t, T, Cf>, uncvref_t<Cf>>>::value;
171 template <
typename T,
typename Cf>
172 struct series_is_rebindable_impl<
173 T, Cf, enable_if_t<disjunction<negation<is_cf<uncvref_t<Cf>>>, negation<is_series<uncvref_t<T>>>>::value>> {
174 static const bool value =
false;
196 template <
typename T,
typename Cf>
199 static const bool implementation_defined = series_is_rebindable_impl<T, Cf>::value;
203 static const bool value = implementation_defined;
206 template <
typename T,
typename Cf>
209 inline namespace impl
214 template <
typename T,
typename Cf>
215 using series_rebind_implementation = enable_if_t<series_is_rebindable<T, Cf>::value, series_rebind_t<T, Cf>>;
224 template <
typename T,
typename Cf>
236 template <
typename T,
typename =
void>
239 static const std::size_t implementation_defined = 0u;
243 static const std::size_t
value = implementation_defined;
246 template <
typename T,
typename Enable>
249 #if !defined(PIRANHA_DOXYGEN_INVOKED) 251 template <
typename T>
253 T, typename
std::enable_if<std::is_base_of<detail::series_tag, typename std::decay<T>::type>::value>::type>
255 using cf_type =
typename std::decay<T>::type::term_type::cf_type;
262 template <
typename T>
263 const std::size_t series_recursion_index<
264 T,
typename std::enable_if<std::is_base_of<detail::series_tag, typename std::decay<T>::type>::value>::type>::value;
274 template <
typename Series>
277 using Sd =
typename std::decay<Series>::type;
279 template <
typename T>
282 static const bool implementation_defined = std::is_same<decltype(test(std::declval<Sd>())), Sd>::
value;
286 static const bool value = implementation_defined;
289 template <
typename Series>
304 template <
typename S>
305 using bso_cf_t =
typename std::enable_if<is_series<S>::value,
typename S::term_type::cf_type>::type;
313 template <
typename,
typename,
int,
typename =
void>
317 template <
typename T,
typename U>
318 struct op_result<T, U, 0, typename
std::enable_if<is_addable<T, U>::value>::type> {
319 using type = decltype(std::declval<const T &>() + std::declval<const U &>());
322 template <
typename T,
typename U>
323 struct op_result<T, U, 1, typename
std::enable_if<is_subtractable<T, U>::value>::type> {
324 using type = decltype(std::declval<const T &>() - std::declval<const U &>());
327 template <
typename T,
typename U>
328 struct op_result<T, U, 2, typename
std::enable_if<is_multipliable<T, U>::value>::type> {
329 using type = decltype(std::declval<const T &>() * std::declval<const U &>());
332 template <
typename T,
typename U>
333 struct op_result<T, U, 3, typename
std::enable_if<is_divisible<T, U>::value>::type> {
334 using type = decltype(std::declval<const T &>() / std::declval<const U &>());
340 template <
typename S1,
typename S2,
int N>
343 typename op_result<bso_cf_t<S1>, bso_cf_t<S2>, N>::type>::type;
348 template <
typename S,
typename T,
int N>
350 typename op_result<bso_cf_t<S>, T, N>::type>::type;
353 template <
typename,
typename,
int,
typename =
void>
354 struct binary_series_op_return_type {
361 template <
typename S1,
typename S2,
int N>
362 struct binary_series_op_return_type<S1, S2, N,
363 typename
std::enable_if<
370 series_recursion_index<S1>::value == series_recursion_index<S2>::value
371 && series_recursion_index<S1>::value != 0u &&
372 std::is_same<bso_cf_op_t<S1, S2, N>, bso_cf_t<S1>>::value
373 && std::is_same<bso_cf_op_t<S1, S2, N>, bso_cf_t<S2>>::value &&
374 std::is_same<S1, S2>::value>::type> {
376 static const unsigned value = 0u;
382 template <
typename S1,
typename S2,
int N>
383 struct binary_series_op_return_type<S1, S2, N,
384 typename
std::enable_if<
385 series_recursion_index<S1>::value == series_recursion_index<S2>::value
386 && series_recursion_index<S1>::value != 0u &&
387 std::is_same<bso_cf_op_t<S1, S2, N>, bso_cf_t<S1>>::value
388 && !std::is_same<bso_cf_t<S1>, bso_cf_t<S2>>::value>::type> {
390 static const unsigned value = 1u;
396 template <
typename S1,
typename S2,
int N>
397 struct binary_series_op_return_type<S1, S2, N,
398 typename
std::enable_if<
399 series_recursion_index<S1>::value == series_recursion_index<S2>::value
400 && series_recursion_index<S1>::value != 0u &&
401 std::is_same<bso_cf_op_t<S1, S2, N>, bso_cf_t<S2>>::value
402 && !std::is_same<bso_cf_t<S1>, bso_cf_t<S2>>::value>::type> {
404 static const unsigned value = 2u;
411 template <
typename S1,
typename S2,
int N>
412 struct binary_series_op_return_type<S1, S2, N,
413 typename
std::enable_if<
414 series_recursion_index<S1>::value == series_recursion_index<S2>::value
415 && series_recursion_index<S1>::value != 0u &&
416 !std::is_same<bso_cf_op_t<S1, S2, N>, bso_cf_t<S1>>::value
417 && !std::is_same<bso_cf_op_t<S1, S2, N>, bso_cf_t<S2>>::value
419 std::is_same<series_rebind<S1, bso_cf_op_t<S1, S2, N>>,
420 series_rebind<S2, bso_cf_op_t<S1, S2, N>>>::value>::type> {
421 using type = series_rebind<S1, bso_cf_op_t<S1, S2, N>>;
422 static const unsigned value = 3u;
428 template <
typename S1,
typename S2,
int N>
429 struct binary_series_op_return_type<S1, S2, N,
430 typename
std::enable_if<
431 (series_recursion_index<S1>::value > series_recursion_index<S2>::value) &&
432 std::is_same<bsom_cf_op_t<S1, S2, N>, bso_cf_t<S1>>::value>::type> {
434 static const unsigned value = 4u;
441 template <
typename S1,
typename S2,
int N>
442 struct binary_series_op_return_type<S1, S2, N,
443 typename
std::enable_if<
444 (series_recursion_index<S1>::value > series_recursion_index<S2>::value) &&
445 !std::is_same<bsom_cf_op_t<S1, S2, N>, bso_cf_t<S1>>::value &&
446 series_is_rebindable<S1, bsom_cf_op_t<S1, S2, N>>::value>::type> {
447 using type = series_rebind<S1, bsom_cf_op_t<S1, S2, N>>;
448 static const unsigned value = 5u;
454 template <
typename S1,
typename S2,
int N>
455 struct binary_series_op_return_type<S1, S2, N,
456 typename
std::enable_if<
457 (series_recursion_index<S2>::value > series_recursion_index<S1>::value) &&
458 std::is_same<bsom_cf_op_t<S2, S1, N>, bso_cf_t<S2>>::value>::type> {
460 static const unsigned value = 6u;
467 template <
typename S1,
typename S2,
int N>
468 struct binary_series_op_return_type<S1, S2, N,
469 typename
std::enable_if<
470 (series_recursion_index<S2>::value > series_recursion_index<S1>::value) &&
471 !std::is_same<bsom_cf_op_t<S2, S1, N>, bso_cf_t<S2>>::value &&
472 series_is_rebindable<S2, bsom_cf_op_t<S2, S1, N>>::value>::type> {
473 using type = series_rebind<S2, bsom_cf_op_t<S2, S1, N>>;
474 static const unsigned value = 7u;
545 template <
typename T,
typename U,
int N>
547 = detail::binary_series_op_return_type<typename std::decay<T>::type,
typename std::decay<U>::type, N>;
548 template <
typename T,
typename U,
int N>
549 using series_common_type =
typename bso_type<T, U, N>::type;
552 template <
bool Sign,
typename T,
typename U>
553 static series_common_type<T, U, 0> binary_add_impl(T &&x, U &&y)
556 using ret_type = series_common_type<T, U, 0>;
557 static_assert(std::is_same<
typename std::decay<T>::type, ret_type>::value,
"Invalid type.");
558 static_assert(std::is_same<
typename std::decay<U>::type, ret_type>::value,
"Invalid type.");
561 ret_type retval(std::forward<T>(x));
566 if (unlikely(&x == &y)) {
567 retval.template merge_terms<Sign>(retval);
571 if (likely(retval.m_symbol_set == y.m_symbol_set)) {
572 retval.template merge_terms<Sign>(std::forward<U>(y));
575 const auto merge =
ss_merge(retval.m_symbol_set, y.m_symbol_set);
576 if (std::get<0>(merge) != retval.m_symbol_set) {
578 retval = retval.merge_arguments(std::get<0>(merge), std::get<1>(merge));
581 if (std::get<0>(merge) != y.m_symbol_set) {
582 retval.template merge_terms<Sign>(y.merge_arguments(std::get<0>(merge), std::get<2>(merge)));
584 retval.template merge_terms<Sign>(std::forward<U>(y));
591 template <typename T, typename U, typename std::enable_if<bso_type<T, U, 0>::value == 0u,
int>::type = 0>
592 static series_common_type<T, U, 0> dispatch_binary_add(T &&x, U &&y)
594 return binary_add_impl<true>(std::forward<T>(x), std::forward<U>(y));
600 template <
typename T,
typename U,
601 typename std::enable_if<
602 (bso_type<T, U, 0>::value == 1u || bso_type<T, U, 0>::value == 4u) &&
604 std::is_constructible<
typename std::decay<T>::type,
const typename std::decay<U>::type &>::value,
607 static series_common_type<T, U, 0> dispatch_binary_add(T &&x, U &&y)
609 typename std::decay<T>::type y1(std::forward<U>(y));
610 return dispatch_binary_add(std::forward<T>(x), std::move(y1));
613 template <typename T, typename U, typename std::enable_if<bso_type<T, U, 0>::value == 2u,
int>::type = 0>
614 static auto dispatch_binary_add(T &&x, U &&y)
615 -> decltype(dispatch_binary_add(std::forward<U>(y), std::forward<T>(x)))
617 return dispatch_binary_add(std::forward<U>(y), std::forward<T>(x));
624 typename T,
typename U,
625 typename std::enable_if<
626 (bso_type<T, U, 0>::value == 3u || bso_type<T, U, 0>::value == 5u) &&
629 std::is_constructible<series_common_type<T, U, 0>,
const typename std::decay<T>::type &>::value
630 && std::is_constructible<series_common_type<T, U, 0>,
const typename std::decay<U>::type &>::value,
633 static series_common_type<T, U, 0> dispatch_binary_add(T &&x, U &&y)
635 series_common_type<T, U, 0> x1(std::forward<T>(x));
636 series_common_type<T, U, 0> y1(std::forward<U>(y));
637 return dispatch_binary_add(std::move(x1), std::move(y1));
640 template <
typename T,
typename U,
641 typename std::enable_if<bso_type<T, U, 0>::value == 6u || bso_type<T, U, 0>::value == 7u,
int>::type = 0>
642 static auto dispatch_binary_add(T &&x, U &&y)
643 -> decltype(dispatch_binary_add(std::forward<U>(y), std::forward<T>(x)))
645 return dispatch_binary_add(std::forward<U>(y), std::forward<T>(x));
652 template <
typename T,
typename... U>
653 using binary_add_type = decltype(dispatch_binary_add(std::declval<
const typename std::decay<T>::type &>(),
654 std::declval<
const typename std::decay<U>::type &>()...));
657 template <
typename T,
typename U,
658 typename std::enable_if<std::is_assignable<T &, binary_add_type<T, U>>::value,
int>::type = 0>
659 static T &dispatch_in_place_add(T &x, U &&y)
662 x = dispatch_binary_add(std::move(x), std::forward<U>(y));
669 template <
typename T,
typename... U>
670 using in_place_add_type
671 = decltype(dispatch_in_place_add(std::declval<T &>(), std::declval<
const typename std::decay<U>::type &>()...));
672 template <
typename T,
typename... U>
673 using in_place_add_enabler =
typename std::enable_if<detail::true_tt<in_place_add_type<T, U...>>::value,
int>::type;
675 template <typename T, typename U, typename std::enable_if<bso_type<T, U, 1>::value == 0u,
int>::type = 0>
676 static series_common_type<T, U, 1> dispatch_binary_sub(T &&x, U &&y)
678 return binary_add_impl<false>(std::forward<T>(x), std::forward<U>(y));
680 template <
typename T,
typename U,
681 typename std::enable_if<(bso_type<T, U, 1>::value == 1u || bso_type<T, U, 1>::value == 4u)
682 && std::is_constructible<
typename std::decay<T>::type,
683 const typename std::decay<U>::type &>::value,
686 static series_common_type<T, U, 1> dispatch_binary_sub(T &&x, U &&y)
688 typename std::decay<T>::type y1(std::forward<U>(y));
689 return dispatch_binary_sub(std::forward<T>(x), std::move(y1));
691 template <typename T, typename U, typename std::enable_if<bso_type<T, U, 1>::value == 2u,
int>::type = 0>
692 static auto dispatch_binary_sub(T &&x, U &&y)
693 -> decltype(dispatch_binary_sub(std::forward<U>(y), std::forward<T>(x)))
695 auto retval = dispatch_binary_sub(std::forward<U>(y), std::forward<T>(x));
700 typename T,
typename U,
701 typename std::enable_if<
702 (bso_type<T, U, 1>::value == 3u || bso_type<T, U, 1>::value == 5u)
703 && std::is_constructible<series_common_type<T, U, 1>,
const typename std::decay<T>::type &>::value
704 && std::is_constructible<series_common_type<T, U, 1>,
const typename std::decay<U>::type &>::value,
707 static series_common_type<T, U, 1> dispatch_binary_sub(T &&x, U &&y)
709 series_common_type<T, U, 1> x1(std::forward<T>(x));
710 series_common_type<T, U, 1> y1(std::forward<U>(y));
711 return dispatch_binary_sub(std::move(x1), std::move(y1));
713 template <
typename T,
typename U,
714 typename std::enable_if<bso_type<T, U, 1>::value == 6u || bso_type<T, U, 1>::value == 7u,
int>::type = 0>
715 static auto dispatch_binary_sub(T &&x, U &&y)
716 -> decltype(dispatch_binary_sub(std::forward<U>(y), std::forward<T>(x)))
718 auto retval = dispatch_binary_sub(std::forward<U>(y), std::forward<T>(x));
722 template <
typename T,
typename... U>
723 using binary_sub_type = decltype(dispatch_binary_sub(std::declval<
const typename std::decay<T>::type &>(),
724 std::declval<
const typename std::decay<U>::type &>()...));
725 template <
typename T,
typename U,
726 typename std::enable_if<std::is_assignable<T &, binary_sub_type<T, U>>::value,
int>::type = 0>
727 static T &dispatch_in_place_sub(T &x, U &&y)
729 x = dispatch_binary_sub(std::move(x), std::forward<U>(y));
732 template <
typename T,
typename... U>
733 using in_place_sub_type
734 = decltype(dispatch_in_place_sub(std::declval<T &>(), std::declval<
const typename std::decay<U>::type &>()...));
735 template <
typename T,
typename... U>
736 using in_place_sub_enabler =
typename std::enable_if<detail::true_tt<in_place_sub_type<T, U...>>::value,
int>::type;
738 struct binary_mul_impl {
739 template <
typename T,
typename U>
740 series_common_type<T, U, 2> operator()(T &&x, U &&y)
const 745 template <typename T, typename U, typename std::enable_if<bso_type<T, U, 2>::value == 0u,
int>::type = 0>
746 static series_common_type<T, U, 2> dispatch_binary_mul(T &&x, U &&y)
748 using ret_type = series_common_type<T, U, 2>;
749 static_assert(std::is_same<
typename std::decay<T>::type, ret_type>::value,
"Invalid type.");
750 static_assert(std::is_same<
typename std::decay<U>::type, ret_type>::value,
"Invalid type.");
751 return series_merge_f(std::forward<T>(x), std::forward<U>(y), binary_mul_impl{});
753 template <
typename T,
typename U,
754 typename std::enable_if<(bso_type<T, U, 2>::value == 1u || bso_type<T, U, 2>::value == 4u)
755 && std::is_constructible<
typename std::decay<T>::type,
756 const typename std::decay<U>::type &>::value,
759 static series_common_type<T, U, 2> dispatch_binary_mul(T &&x, U &&y)
761 typename std::decay<T>::type y1(std::forward<U>(y));
762 return dispatch_binary_mul(std::forward<T>(x), std::move(y1));
764 template <typename T, typename U, typename std::enable_if<bso_type<T, U, 2>::value == 2u,
int>::type = 0>
765 static auto dispatch_binary_mul(T &&x, U &&y)
766 -> decltype(dispatch_binary_mul(std::forward<U>(y), std::forward<T>(x)))
768 return dispatch_binary_mul(std::forward<U>(y), std::forward<T>(x));
771 typename T,
typename U,
772 typename std::enable_if<
773 (bso_type<T, U, 2>::value == 3u || bso_type<T, U, 2>::value == 5u)
774 && std::is_constructible<series_common_type<T, U, 2>,
const typename std::decay<T>::type &>::value
775 && std::is_constructible<series_common_type<T, U, 2>,
const typename std::decay<U>::type &>::value,
778 static series_common_type<T, U, 2> dispatch_binary_mul(T &&x, U &&y)
780 series_common_type<T, U, 2> x1(std::forward<T>(x));
781 series_common_type<T, U, 2> y1(std::forward<U>(y));
782 return dispatch_binary_mul(std::move(x1), std::move(y1));
784 template <
typename T,
typename U,
785 typename std::enable_if<bso_type<T, U, 2>::value == 6u || bso_type<T, U, 2>::value == 7u,
int>::type = 0>
786 static auto dispatch_binary_mul(T &&x, U &&y)
787 -> decltype(dispatch_binary_mul(std::forward<U>(y), std::forward<T>(x)))
789 return dispatch_binary_mul(std::forward<U>(y), std::forward<T>(x));
793 template <
typename T,
typename... U>
794 using binary_mul_type_ = decltype(dispatch_binary_mul(std::declval<
const typename std::decay<T>::type &>(),
795 std::declval<
const typename std::decay<U>::type &>()...));
796 template <
typename T,
typename... U>
797 using binary_mul_type =
typename std::enable_if<
series_has_multiplier<binary_mul_type_<T, U...>>::value,
798 binary_mul_type_<T, U...>>::type;
799 template <
typename T,
typename U,
800 typename std::enable_if<std::is_assignable<T &, binary_mul_type<T, U>>::value,
int>::type = 0>
801 static T &dispatch_in_place_mul(T &x, U &&y)
803 x = dispatch_binary_mul(std::move(x), std::forward<U>(y));
806 template <
typename T,
typename... U>
807 using in_place_mul_type
808 = decltype(dispatch_in_place_mul(std::declval<T &>(), std::declval<
const typename std::decay<U>::type &>()...));
809 template <
typename T,
typename... U>
810 using in_place_mul_enabler =
typename std::enable_if<detail::true_tt<in_place_mul_type<T, U...>>::value,
int>::type;
814 template <typename T, typename U, typename std::enable_if<bso_type<T, U, 3>::value == 0u,
int>::type = 0>
815 static series_common_type<T, U, 3> dispatch_binary_div(T &&x, U &&y)
817 using ret_type = series_common_type<T, U, 3>;
818 using term_type =
typename ret_type::term_type;
819 using cf_type =
typename term_type::cf_type;
820 using key_type =
typename term_type::key_type;
821 if (!y.is_single_coefficient()) {
822 piranha_throw(std::invalid_argument,
"divisor in series division does not consist of a single coefficient");
824 const auto y_cf = y.empty() ? cf_type(0) : y._container().begin()->m_cf;
827 retval.insert(term_type{cf_type{0} / y_cf, key_type{retval.get_symbol_set()}});
833 template <
typename T,
typename U,
834 typename std::enable_if<bso_type<T, U, 3>::value == 1u
835 && std::is_constructible<typename std::decay<T>::type,
836 const typename std::decay<U>::type &>::value,
839 static series_common_type<T, U, 3> dispatch_binary_div(T &&x, U &&y)
841 typename std::decay<T>::type y1(std::forward<U>(y));
842 return dispatch_binary_div(std::forward<T>(x), std::move(y1));
847 template <
typename T,
typename U,
848 typename std::enable_if<(bso_type<T, U, 3>::value == 2u || bso_type<T, U, 3>::value == 6u)
849 && std::is_constructible<
typename std::decay<U>::type,
850 const typename std::decay<T>::type &>::value,
853 static series_common_type<T, U, 3> dispatch_binary_div(T &&x, U &&y)
855 typename std::decay<U>::type x1(std::forward<T>(x));
856 return dispatch_binary_div(std::move(x1), std::forward<U>(y));
862 typename T,
typename U,
863 typename std::enable_if<
864 (bso_type<T, U, 3>::value == 3u || bso_type<T, U, 3>::value == 7u)
865 && std::is_constructible<series_common_type<T, U, 3>,
const typename std::decay<T>::type &>::value
866 && std::is_constructible<series_common_type<T, U, 3>,
const typename std::decay<U>::type &>::value,
869 static series_common_type<T, U, 3> dispatch_binary_div(T &&x, U &&y)
871 series_common_type<T, U, 0> x1(std::forward<T>(x));
872 series_common_type<T, U, 0> y1(std::forward<U>(y));
873 return dispatch_binary_div(std::move(x1), std::move(y1));
886 template <typename T, typename U, typename std::enable_if<bso_type<T, U, 3>::value == 4u,
int>::type = 0>
887 static series_common_type<T, U, 3>
888 dispatch_binary_div(T &&x, U &&y,
889 typename std::enable_if<
has_is_zero<
typename std::decay<U>::type>::value>::type * =
nullptr)
891 using ret_type = series_common_type<T, U, 3>;
894 using term_type =
typename ret_type::term_type;
895 using cf_type =
typename term_type::cf_type;
896 using key_type =
typename term_type::key_type;
898 retval.insert(term_type{cf_type{0} / y, key_type{retval.get_symbol_set()}});
901 static_assert(std::is_same<
typename std::decay<T>::type, ret_type>::value,
"Invalid type.");
903 ret_type retval(std::forward<T>(x));
905 const auto it_f = retval.m_container.end();
907 for (
auto it = retval.m_container.begin(); it != it_f;) {
914 if (unlikely(it->is_zero(retval.m_symbol_set))) {
916 it = retval.m_container.erase(it);
923 retval.m_container.clear();
931 template <
typename T,
typename U,
932 typename std::enable_if<bso_type<T, U, 3>::value == 5u
933 && std::is_constructible<series_common_type<T, U, 3>,
934 const typename std::decay<T>::type &>::value,
937 static auto dispatch_binary_div(T &&x, U &&y)
938 -> decltype(dispatch_binary_div(std::declval<
const series_common_type<T, U, 3> &>(), std::forward<U>(y)))
940 series_common_type<T, U, 3> x1(std::forward<T>(x));
941 return dispatch_binary_div(std::move(x1), std::forward<U>(y));
943 template <
typename T,
typename... U>
944 using binary_div_type = decltype(dispatch_binary_div(std::declval<
const typename std::decay<T>::type &>(),
945 std::declval<
const typename std::decay<U>::type &>()...));
946 template <
typename T,
typename U,
947 typename std::enable_if<std::is_assignable<T &, binary_div_type<T, U>>::value,
int>::type = 0>
948 static T &dispatch_in_place_div(T &x, U &&y)
950 x = dispatch_binary_div(std::move(x), std::forward<U>(y));
953 template <
typename T,
typename... U>
954 using in_place_div_type
955 = decltype(dispatch_in_place_div(std::declval<T &>(), std::declval<
const typename std::decay<U>::type &>()...));
956 template <
typename T,
typename... U>
957 using in_place_div_enabler =
typename std::enable_if<detail::true_tt<in_place_div_type<T, U...>>::value,
int>::type;
960 template <
typename T>
961 static bool equality_impl(
const T &x,
const T &y)
963 if (x.size() != y.size()) {
971 piranha_assert(x.m_symbol_set == y.m_symbol_set);
972 const auto it_f_x = x.m_container.end(), it_f_y = y.m_container.end();
973 for (
auto it = x.m_container.begin(); it != it_f_x; ++it) {
974 const auto tmp_it = y.m_container.find(*it);
975 if (tmp_it == it_f_y || tmp_it->m_cf != it->m_cf) {
982 template <typename T, typename U, typename std::enable_if<bso_type<T, U, 0>::value == 0u,
int>::type = 0>
983 static bool dispatch_equality(
const T &x,
const U &y)
985 static_assert(std::is_same<T, U>::value,
"Invalid types for the equality operator.");
986 return series_merge_f(x, y, [](
const T &a,
const T &b) {
return series_operators::equality_impl(a, b); });
988 template <
typename T,
typename U,
989 typename std::enable_if<(bso_type<T, U, 0>::value == 1u || bso_type<T, U, 0>::value == 4u)
990 && std::is_constructible<T, const U &>::value,
993 static bool dispatch_equality(
const T &x,
const U &y)
995 return dispatch_equality(x, T(y));
997 template <typename T, typename U, typename std::enable_if<bso_type<T, U, 0>::value == 2u,
int>::type = 0>
998 static auto dispatch_equality(
const T &x,
const U &y) -> decltype(dispatch_equality(y, x))
1000 return dispatch_equality(y, x);
1002 template <
typename T,
typename U,
1003 typename std::enable_if<(bso_type<T, U, 0>::value == 3u || bso_type<T, U, 0>::value == 5u)
1004 && std::is_constructible<series_common_type<T, U, 0>,
const T &>::value
1005 && std::is_constructible<series_common_type<T, U, 0>,
const U &>::value,
1008 static bool dispatch_equality(
const T &x,
const U &y)
1010 series_common_type<T, U, 0> x1(x);
1011 series_common_type<T, U, 0> y1(y);
1012 return dispatch_equality(x1, y1);
1014 template <
typename T,
typename U,
1015 typename std::enable_if<bso_type<T, U, 0>::value == 6u || bso_type<T, U, 0>::value == 7u,
int>::type = 0>
1016 static auto dispatch_equality(
const T &x,
const U &y) -> decltype(dispatch_equality(y, x))
1018 return dispatch_equality(y, x);
1020 template <
typename T,
typename... U>
1021 using eq_type = decltype(dispatch_equality(std::declval<
const typename std::decay<T>::type &>(),
1022 std::declval<
const typename std::decay<U>::type &>()...));
1023 template <
typename T,
typename... U>
1024 using eq_enabler =
typename std::enable_if<detail::true_tt<eq_type<T, U...>>::value,
int>::type;
1043 template <
typename T,
typename... U>
1046 return dispatch_binary_add(std::forward<T>(x), std::forward<U>(y)...);
1061 template <
typename T,
typename... U, in_place_add_enabler<T, U...> = 0>
1064 return dispatch_in_place_add(x, std::forward<U>(y)...);
1083 template <
typename T,
typename... U>
1086 return dispatch_binary_sub(std::forward<T>(x), std::forward<U>(y)...);
1101 template <
typename T,
typename... U, in_place_sub_enabler<T, U...> = 0>
1104 return dispatch_in_place_sub(x, std::forward<U>(y)...);
1123 template <
typename T,
typename... U>
1126 return dispatch_binary_mul(std::forward<T>(x), std::forward<U>(y)...);
1141 template <
typename T,
typename... U, in_place_mul_enabler<T, U...> = 0>
1144 return dispatch_in_place_mul(x, std::forward<U>(y)...);
1163 template <
typename T,
typename... U>
1166 return dispatch_binary_div(std::forward<T>(x), std::forward<U>(y)...);
1181 template <
typename T,
typename... U, in_place_div_enabler<T, U...> = 0>
1184 return dispatch_in_place_div(x, std::forward<U>(y)...);
1206 template <
typename T,
typename... U, eq_enabler<T, U...> = 0>
1209 return dispatch_equality(x, y...);
1224 template <
typename T,
typename... U, eq_enabler<T, U...> = 0>
1227 return !dispatch_equality(x, y...);
1261 template <
typename Cf,
typename Key,
typename Derived>
1262 class series : detail::series_tag, series_operators
1270 template <
typename,
typename,
typename>
1278 template <
typename,
typename>
1280 #if !defined(PIRANHA_DOXYGEN_INVOKED) 1282 template <
typename S1,
typename S2,
typename F>
1283 friend auto impl::series_merge_f(S1 &&s1, S2 &&s2,
const F &f)
1284 -> decltype(f(std::forward<S1>(s1), std::forward<S2>(s2)));
1292 #if !defined(PIRANHA_DOXYGEN_INVOKED) 1294 typedef decltype(std::declval<container_type>().evaluate_sparsity()) sparsity_info_type;
1296 template <
bool Sign, typename T>
1297 void dispatch_insertion(
1299 typename
std::enable_if<
std::is_same<typename
std::decay<T>::type,
term_type>::value>::type * =
nullptr)
1302 piranha_assert(empty() || m_container.begin()->is_compatible(m_symbol_set));
1305 piranha_throw(std::invalid_argument,
"cannot insert incompatible term");
1311 insertion_impl<Sign>(std::forward<T>(
term));
1314 template <
bool Sign,
typename Iterator>
1315 static void insertion_cf_arithmetics(Iterator &it,
const term_type &
term)
1320 it->m_cf -= term.m_cf;
1323 template <
bool Sign,
typename Iterator>
1324 static void insertion_cf_arithmetics(Iterator &it, term_type &&term)
1327 it->m_cf += std::move(term.m_cf);
1329 it->m_cf -= std::move(term.m_cf);
1333 template <
bool Sign,
typename T>
1334 void insertion_impl(T &&term)
1339 if (unlikely(!m_container.bucket_count())) {
1340 m_container._increase_size();
1343 auto bucket_idx = m_container._bucket(term);
1344 const auto it = m_container._find(term, bucket_idx);
1347 auto cleanup = [
this](
const typename container_type::const_iterator &it_c) {
1348 if (unlikely(it_c->is_zero(this->m_symbol_set))) {
1349 this->m_container.erase(it_c);
1352 if (it == m_container.end()) {
1353 if (unlikely(m_container.size() == std::numeric_limits<size_type>::max())) {
1354 piranha_throw(std::overflow_error,
"maximum number of elements reached");
1357 if (unlikely(static_cast<double>(m_container.size() + size_type(1u))
1358 / static_cast<double>(m_container.bucket_count())
1359 > m_container.max_load_factor())) {
1360 m_container._increase_size();
1362 bucket_idx = m_container._bucket(term);
1364 const auto new_it = m_container._unique_insert(std::forward<T>(term), bucket_idx);
1365 m_container._update_size(m_container.size() + size_type(1u));
1380 piranha_assert(!it->is_zero(m_symbol_set) && it->is_compatible(m_symbol_set));
1383 insertion_cf_arithmetics<Sign>(it, std::forward<T>(term));
1392 template <
typename T>
1393 using insert_enabler =
1394 typename std::enable_if<std::is_same<term_type, typename std::decay<T>::type>::value,
int>::type;
1401 template <
bool Sign,
typename T>
1402 void merge_terms_impl0(T &&s)
1406 if (unlikely(&s ==
this)) {
1410 merge_terms_impl1<Sign>(series<Cf, Key, Derived>(
static_cast<const series<Cf, Key, Derived> &
>(s)));
1412 merge_terms_impl1<Sign>(std::forward<T>(s));
1416 template <
bool Sign,
typename T>
1417 void merge_terms_impl1(T &&s,
typename std::enable_if<!is_nonconst_rvalue_ref<T &&>::value>::type * =
nullptr)
1419 const auto it_f = s.m_container.end();
1421 for (
auto it = s.m_container.begin(); it != it_f; ++it) {
1426 m_container.clear();
1430 static void swap_for_merge(container_type &&c1, container_type &&c2,
bool &swap)
1432 piranha_assert(!swap);
1434 if (unlikely(c1.size() > std::numeric_limits<size_type>::max() - c2.size())) {
1438 const auto max_size = c1.size() + c2.size();
1440 size_type max_n_buckets;
1442 piranha_assert(c1.max_load_factor() > 0);
1444 = boost::numeric_cast<size_type>(std::trunc(static_cast<double>(max_size) / c1.max_load_factor()));
1451 if (c1.bucket_count() < max_n_buckets && c2.bucket_count() > c1.bucket_count()) {
1452 container_type tmp(std::move(c1));
1454 c2 = std::move(tmp);
1460 template <
typename OtherContainerType>
1461 static void swap_for_merge(container_type &&, OtherContainerType &&,
bool &)
1465 template <
bool Sign,
typename T>
1466 void merge_terms_impl1(T &&s,
typename std::enable_if<is_nonconst_rvalue_ref<T &&>::value>::type * =
nullptr)
1470 swap_for_merge(std::move(m_container), std::move(s.m_container), swap);
1472 const auto it_f = s.m_container._m_end();
1473 for (
auto it = s.m_container._m_begin(); it != it_f; ++it) {
1474 insert<Sign>(std::move(*it));
1478 if (swap && !Sign) {
1479 const auto it_f2 = m_container.end();
1480 for (
auto it = m_container.begin(); it != it_f2;) {
1482 if (unlikely(it->is_zero(m_symbol_set))) {
1484 it = m_container.erase(it);
1492 m_container.clear();
1493 s.m_container.clear();
1497 s.m_container.clear();
1501 template <
bool Sign,
typename T>
1502 void merge_terms(T &&s,
typename std::enable_if<is_series<
typename std::decay<T>::type>::value>::type * =
nullptr)
1504 static_assert(std::is_base_of<series<Cf, Key, Derived>,
typename std::decay<T>::type>::value,
"Type error.");
1505 merge_terms_impl0<Sign>(std::forward<T>(s));
1509 template <
typename T,
typename U = series,
1514 void dispatch_generic_constructor(
const T &x)
1516 typedef typename term_type::cf_type cf_type;
1517 typedef typename term_type::key_type key_type;
1518 cf_type cf(convert_to<cf_type>(x));
1519 key_type key(m_symbol_set);
1520 insert(term_type(std::move(cf), std::move(key)));
1530 template <
typename T,
typename U = series,
1531 typename std::enable_if<
1538 void dispatch_generic_constructor(
const T &s)
1540 typedef typename term_type::cf_type cf_type;
1541 typedef typename term_type::key_type key_type;
1542 m_symbol_set = s.m_symbol_set;
1543 const auto it_f = s.m_container.end();
1545 for (
auto it = s.m_container.begin(); it != it_f; ++it) {
1546 insert<true>(term_type(convert_to<cf_type>(it->m_cf), key_type(it->m_key, m_symbol_set)));
1550 m_container.clear();
1566 template <
typename T,
typename U>
1567 using generic_ctor_enabler =
typename std::enable_if<
1568 detail::true_tt<decltype(std::declval<U &>().dispatch_generic_constructor(std::declval<const T &>()))>::value
1569 && !std::is_base_of<U, T>::value,
1572 template <
typename T>
1573 using is_identical_enabler =
typename std::enable_if<is_equality_comparable<T>::value,
int>::type;
1575 typedef boost::transform_iterator<std::function<std::pair<typename term_type::cf_type, Derived>(
const term_type &)>,
1576 typename container_type::const_iterator>
1577 const_iterator_impl;
1579 template <
bool TexMode,
typename Iterator>
1580 static std::ostream &print_helper(std::ostream &os, Iterator start, Iterator end,
const symbol_fset &args)
1582 piranha_assert(start != end);
1584 size_type count = 0u;
1585 std::ostringstream oss;
1587 for (; it != end;) {
1588 if (limit && count == limit) {
1591 std::ostringstream oss_cf;
1597 auto str_cf = oss_cf.str();
1598 std::ostringstream oss_key;
1600 it->m_key.print_tex(oss_key, args);
1602 it->m_key.print(oss_key, args);
1604 auto str_key = oss_key.str();
1605 if (str_cf ==
"1" && !str_key.empty()) {
1607 }
else if (str_cf ==
"-1" && !str_key.empty()) {
1611 if (str_cf !=
"" && str_cf !=
"-" && !str_key.empty() && !TexMode) {
1621 auto str = oss.str();
1623 if (limit && count == limit && it != end) {
1630 std::string::size_type index = 0u;
1632 index = str.find(
"+-", index);
1633 if (index == std::string::npos) {
1636 str.replace(index, 2u,
"-");
1644 Derived merge_arguments(
const symbol_fset &new_s,
const symbol_idx_fmap<symbol_fset> &m)
const 1647 piranha_assert(m.size());
1651 piranha_assert(m.rbegin()->first <= m_symbol_set.size());
1652 #if !defined(NDEBUG) 1655 auto verify_ins_map = [&m]() ->
bool {
1656 std::vector<std::string> v_str;
1657 for (
const auto &p : m) {
1658 v_str.insert(v_str.end(), p.second.begin(), p.second.end());
1660 return std::is_sorted(v_str.begin(), v_str.end())
1661 && std::adjacent_find(v_str.begin(), v_str.end()) == v_str.end();
1664 auto verify_ss = [&m, &new_s]() ->
bool {
1665 for (
const auto &p : m) {
1666 for (
const auto &s : p.second) {
1667 if (new_s.find(s) == new_s.end()) {
1675 piranha_assert(verify_ins_map());
1676 piranha_assert(verify_ss());
1680 retval.m_symbol_set = new_s;
1682 retval.m_container.rehash(this->m_container.bucket_count());
1684 const auto it_f = m_container.end();
1685 for (
auto it = m_container.begin(); it != it_f; ++it) {
1686 retval.insert(term_type{it->m_cf, it->m_key.merge_symbols(m, this->m_symbol_set)});
1691 bool destruction_checks()
const 1697 for (
auto it = m_container.begin(); it != m_container.end(); ++it) {
1698 if (!it->is_compatible(m_symbol_set)) {
1699 std::cout <<
"Term not compatible.\n";
1702 if (it->is_zero(m_symbol_set)) {
1703 std::cout <<
"Term not ignorable.\n";
1709 template <
typename T>
1710 static T trim_cf_impl(
const T &s,
typename std::enable_if<
is_series<T>::value>::type * =
nullptr)
1714 template <
typename T>
1715 static const T &trim_cf_impl(
const T &s,
typename std::enable_if<!
is_series<T>::value>::type * =
nullptr)
1720 template <
typename Cf2>
1721 using cf_diff_type = decltype(
math::partial(std::declval<const Cf2 &>(), std::string()));
1724 template <
typename Key2>
1726 = decltype(std::declval<const Key2 &>().
partial(
symbol_idx{}, std::declval<const symbol_fset &>()).first);
1728 template <
typename Series>
1729 using cf_t =
typename Series::term_type::cf_type;
1730 template <
typename Series>
1731 using key_t =
typename Series::term_type::key_type;
1736 template <
typename Series,
typename =
void>
1737 struct partial_type_ {
1742 #define PIRANHA_SERIES_PARTIAL_ENABLER \ 1743 (std::is_same<cf_diff_type<cf_t<Series>>, cf_t<Series>>::value \ 1744 && std::is_same<decltype(std::declval<const cf_t<Series> &>() \ 1745 * std::declval<const key_diff_type<key_t<Series>> &>()), \ 1746 cf_t<Series>>::value) 1747 template <
typename Series>
1748 struct partial_type_<Series, typename
std::enable_if<PIRANHA_SERIES_PARTIAL_ENABLER>::type> {
1749 using type = Series;
1751 static const int algo = 0;
1754 template <
typename Series>
1755 using partial_type_1
1756 = decltype(std::declval<
const cf_diff_type<cf_t<Series>> &>() * std::declval<const Series &>()
1757 + std::declval<
const cf_t<Series> &>() * std::declval<
const key_diff_type<key_t<Series>> &>()
1758 * std::declval<const Series &>());
1761 template <
typename Series>
1762 struct partial_type_<
1763 Series, typename
std::enable_if<
1764 !PIRANHA_SERIES_PARTIAL_ENABLER && std::is_constructible<partial_type_1<Series>, int>::value
1765 && is_addable_in_place<decltype(std::declval<const partial_type_1<Series> &>()
1766 + std::declval<const partial_type_1<Series> &>())>::value>::type> {
1767 using type = partial_type_1<Series>;
1768 static const int algo = 1;
1770 #undef PIRANHA_SERIES_PARTIAL_ENABLER 1772 template <
typename Series>
1773 using partial_type =
typename std::enable_if<is_returnable<typename partial_type_<Series>::type>::value,
1774 typename partial_type_<Series>::type>::type;
1776 template <typename Series = Derived, typename std::enable_if<partial_type_<Series>::algo == 0,
int>::type = 0>
1777 partial_type<Series> partial_impl(
const std::string &name)
const 1779 static_assert(std::is_same<Derived, partial_type<Series>>::value,
"Invalid type.");
1782 retval.m_symbol_set = this->m_symbol_set;
1784 retval.m_container.rehash(this->m_container.bucket_count());
1785 const auto pos =
ss_index_of(retval.m_symbol_set, name);
1786 const auto it_f = this->m_container.end();
1787 for (
auto it = this->m_container.begin(); it != it_f; ++it) {
1791 retval.insert(term_type{
math::partial(it->m_cf, name), it->m_key});
1793 auto p_key = it->m_key.partial(pos, retval.m_symbol_set);
1794 retval.insert(term_type{it->m_cf * p_key.first, std::move(p_key.second)});
1798 template <typename Series = Derived, typename std::enable_if<partial_type_<Series>::algo == 1,
int>::type = 0>
1799 partial_type<Series> partial_impl(
const std::string &name)
const 1801 const auto pos =
ss_index_of(this->m_symbol_set, name);
1802 partial_type<Series> retval(0);
1803 const auto it_f = this->m_container.end();
1804 for (
auto it = this->m_container.begin(); it != it_f; ++it) {
1808 tmp0.m_symbol_set = this->m_symbol_set;
1809 tmp0.insert(term_type{1, it->m_key});
1810 auto p_key = it->m_key.partial(pos, this->m_symbol_set);
1812 tmp1.m_symbol_set = this->m_symbol_set;
1813 tmp1.insert(term_type{1, std::move(p_key.second)});
1815 retval +=
math::partial(it->m_cf, name) * tmp0 + it->m_cf * p_key.first * tmp1;
1822 template <
typename Series>
1823 using series_p_type = decltype(
math::partial(std::declval<const Series &>(), std::declval<const std::string &>()));
1824 template <
typename Series>
1825 using cp_map_type = std::unordered_map<std::string, std::function<series_p_type<Series>(
const Derived &)>>;
1828 template <
typename Series = Derived>
1829 static cp_map_type<Series> &get_cp_map()
1831 static cp_map_type<Series> cp_map;
1834 template <
typename F,
typename Series>
1835 using custom_partial_enabler =
1836 typename std::enable_if<std::is_constructible<std::function<series_p_type<Series>(
const Derived &)>, F>::value,
1839 friend class boost::serialization::access;
1840 template <
class Archive>
1841 void save(Archive &ar,
unsigned)
const 1845 for (
const auto &sym : get_symbol_set()) {
1850 for (
const auto &t : _container()) {
1852 boost_save(ar, boost_s11n_key_wrapper<typename term_type::key_type>{t.m_key, get_symbol_set()});
1855 template <
class Archive>
1856 void load(Archive &ar,
unsigned)
1858 using ss_size_t = decltype(get_symbol_set().size());
1859 using s_size_t = decltype(size());
1869 std::vector<std::string> vs;
1870 vs.resize(
safe_cast<std::vector<std::string>::size_type>(ss_size));
1872 for (
auto &str : vs) {
1883 _container().rehash(
1884 boost::numeric_cast<s_size_t>(std::ceil(static_cast<double>(s_size) / _container().max_load_factor())));
1886 for (s_size_t i = 0u; i < s_size; ++i) {
1892 boost_s11n_key_wrapper<typename term_type::key_type> w{t.m_key, ss};
1894 insert(std::move(t));
1897 BOOST_SERIALIZATION_SPLIT_MEMBER()
1900 template <typename T, typename U>
1902 = decltype(math::pow(
std::declval<const typename U::term_type::cf_type &>(),
std::declval<const T &>()));
1904 template <typename U>
1905 using pow_m_type = decltype(
std::declval<const U &>() *
std::declval<const U &>());
1907 template <typename T>
1908 using pow_expo_checks =
std::integral_constant<
bool, conjunction<has_is_zero<T>, has_safe_cast<
integer, T>>::value>;
1910 struct series_hasher {
1911 template <
typename T>
1912 std::size_t operator()(
const T &s)
const 1917 struct series_equal_to {
1918 template <
typename T>
1919 bool operator()(
const T &a,
const T &b)
const 1921 return a.is_identical(b);
1924 template <
typename Series>
1925 using pow_map_type = std::unordered_map<Series, std::vector<pow_m_type<Series>>, series_hasher, series_equal_to>;
1930 template <
typename Series = Derived>
1931 static pow_map_type<Series> &get_pow_cache()
1933 static pow_map_type<Series> s_pow_cache;
1937 template <
typename T,
typename U,
typename =
void>
1938 struct pow_ret_type_ {
1941 template <
typename T,
typename U>
1942 struct pow_ret_type_<
1944 enable_if_t<conjunction<
1945 std::is_same<pow_cf_type<T, U>, typename U::term_type::cf_type>, pow_expo_checks<T>,
1948 std::is_constructible<U, pow_m_type<U>>,
1951 std::is_same<pow_m_type<U>, decltype(std::declval<const pow_m_type<U> &>() * std::declval<const U &>())>,
1953 std::is_same<is_identical_enabler<U>, int>>::value>> {
1957 template <
typename T,
typename U>
1958 struct pow_ret_type_<
1960 enable_if_t<conjunction<
1961 negation<
std::is_same<pow_cf_type<T, U>, typename U::term_type::cf_type>>, pow_expo_checks<T>,
1964 std::is_constructible<series_rebind<U, pow_cf_type<T, U>>, pow_m_type<U>>,
1967 std::is_same<pow_m_type<U>, decltype(std::declval<const pow_m_type<U> &>() * std::declval<const U &>())>,
1969 std::is_same<is_identical_enabler<U>, int>>::value>> {
1970 using type = series_rebind<U, pow_cf_type<T, U>>;
1973 template <
typename T,
typename U>
1974 using pow_ret_type =
typename pow_ret_type_<T, U>::type;
2032 template <
typename T,
typename U = series,
generic_ctor_enabler<T, U> = 0>
2035 dispatch_generic_constructor(x);
2045 piranha_assert(destruction_checks());
2057 if (likely(
this != &other)) {
2059 *
this = std::move(tmp);
2084 template <
typename T,
typename U = series,
generic_ctor_enabler<T, U> = 0>
2087 static_assert(!std::is_base_of<series, T>::value,
"Generic assignment should not be enabled with " 2088 "a type deriving from the calling series.");
2089 return operator=(
series(x));
2097 return m_container.size();
2120 return (empty() || (size() == 1u && m_container.begin()->m_key.is_unitary(m_symbol_set)));
2160 template <
bool Sign,
typename T, insert_enabler<T> = 0>
2163 dispatch_insertion<Sign>(std::forward<T>(
term));
2176 template <
typename T, insert_enabler<T> = 0>
2179 insert<true>(std::forward<T>(
term));
2189 return Derived(*static_cast<Derived const *>(
this));
2201 Derived retval(*static_cast<Derived const *>(
this));
2217 const auto it_f = m_container.end();
2218 for (
auto it = m_container.begin(); it != it_f;) {
2220 if (unlikely(it->is_zero(m_symbol_set))) {
2221 it = m_container.erase(it);
2227 m_container.clear();
2246 return m_container.evaluate_sparsity();
2257 return m_container.load_factor();
2265 return m_container.bucket_count();
2303 template <
typename T,
typename U = Derived>
2304 pow_ret_type<T, U>
pow(
const T &x)
const 2310 using ret_type = pow_ret_type<T, U>;
2311 using r_term_type =
typename ret_type::term_type;
2312 using r_cf_type =
typename r_term_type::cf_type;
2315 using m_type = pow_m_type<Derived>;
2316 using m_term_type =
typename m_type::term_type;
2317 using m_cf_type =
typename m_term_type::cf_type;
2318 using m_key_type =
typename m_term_type::key_type;
2320 if (is_single_coefficient()) {
2333 retval.insert(r_term_type(r_cf_type(1), key_type(
symbol_fset{})));
2341 piranha_throw(std::invalid_argument,
"invalid argument for series exponentiation: non-integral value");
2344 piranha_throw(std::invalid_argument,
"invalid argument for series exponentiation: negative integral value");
2347 std::lock_guard<std::mutex> lock(s_pow_mutex);
2348 auto &v = get_pow_cache()[*
static_cast<Derived
const *
>(
this)];
2349 using s_type = decltype(v.size());
2353 tmp.insert(m_term_type(m_cf_type(1), m_key_type(
symbol_fset{})));
2354 v.push_back(std::move(tmp));
2357 while (v.size() <= n) {
2360 v.push_back(v.back() * (*
static_cast<Derived
const *
>(
this)));
2362 return ret_type(v[static_cast<s_type>(n)]);
2370 template <
typename T = Derived, is_
identical_enabler<T> = 0>
2373 std::lock_guard<std::mutex> lock(s_pow_mutex);
2374 get_pow_cache().clear();
2404 template <
typename Series = Derived>
2405 partial_type<Series>
partial(
const std::string &name)
const 2407 return partial_impl(name);
2431 template <
typename F,
typename Series = Derived, custom_partial_enabler<F, Series> = 0>
2434 using p_type = series_p_type<Derived>;
2435 using f_type = std::function<p_type(const Derived &)>;
2436 std::lock_guard<std::mutex> lock(s_cp_mutex);
2437 get_cp_map()[name] = f_type(func);
2458 template <
typename Series = Derived,
typename Partial = partial_type<Series>>
2461 std::lock_guard<std::mutex> lock(s_cp_mutex);
2462 auto it = get_cp_map().find(name);
2463 if (it != get_cp_map().end()) {
2464 get_cp_map().erase(it);
2477 template <
typename Series = Derived,
typename Partial = partial_type<Series>>
2480 std::lock_guard<std::mutex> lock(s_cp_mutex);
2481 get_cp_map().clear();
2506 typedef std::function<std::pair<typename term_type::cf_type, Derived>(
const term_type &)> func_type;
2508 = [
this](
const term_type &t) {
return detail::pair_from_term<term_type, Derived>(this->m_symbol_set, t); };
2509 return boost::make_transform_iterator(m_container.begin(), func_type(std::move(func)));
2525 typedef std::function<std::pair<typename term_type::cf_type, Derived>(
const term_type &)> func_type;
2527 = [
this](
const term_type &t) {
return detail::pair_from_term<term_type, Derived>(this->m_symbol_set, t); };
2528 return boost::make_transform_iterator(m_container.end(), func_type(std::move(func)));
2547 Derived
filter(std::function<
bool(
const std::pair<typename term_type::cf_type, Derived> &)> func)
const 2550 retval.m_symbol_set = m_symbol_set;
2551 const auto it_f = this->m_container.end();
2552 for (
auto it = this->m_container.begin(); it != it_f; ++it) {
2553 if (func(detail::pair_from_term<term_type, Derived>(m_symbol_set, *it))) {
2585 Derived
transform(std::function<std::pair<typename term_type::cf_type, Derived>(
2586 const std::pair<typename term_type::cf_type, Derived> &)>
2590 std::pair<typename term_type::cf_type, Derived> tmp;
2591 const auto it_f = this->m_container.end();
2592 for (
auto it = this->m_container.begin(); it != it_f; ++it) {
2593 tmp = func(detail::pair_from_term<term_type, Derived>(m_symbol_set, *it));
2596 retval += tmp.first * tmp.second;
2622 std::vector<char> trim_mask(
safe_cast<std::vector<char>::size_type>(m_symbol_set.size()),
char(1));
2624 const auto it_f = this->m_container.end();
2625 for (
auto it = this->m_container.begin(); it != it_f; ++it) {
2626 it->m_key.trim_identify(trim_mask, m_symbol_set);
2630 retval.m_symbol_set =
ss_trim(m_symbol_set, trim_mask);
2631 for (
auto it = this->m_container.begin(); it != it_f; ++it) {
2632 retval.insert(
term_type{trim_cf_impl(it->m_cf), it->
m_key.trim(trim_mask, m_symbol_set)});
2661 print_helper<true>(os, m_container.begin(), m_container.end(), m_symbol_set);
2732 std::size_t retval = 0u;
2733 const auto it_f = m_container.end();
2734 for (
auto it = m_container.begin(); it != it_f; ++it) {
2735 retval += it->hash();
2753 template <
typename T = Derived, is_
identical_enabler<T> = 0>
2756 return m_symbol_set == other.m_symbol_set && other == *
static_cast<Derived
const *
>(
this);
2764 return m_symbol_set;
2775 if (unlikely(!empty())) {
2776 piranha_throw(std::invalid_argument,
"cannot set arguments on a non-empty series");
2778 m_symbol_set = args;
2809 static std::mutex s_cp_mutex;
2811 static std::mutex s_pow_mutex;
2814 template <
typename Cf,
typename Key,
typename Derived>
2817 template <
typename Cf,
typename Key,
typename Derived>
2820 inline namespace impl
2826 template <
typename S1,
typename S2,
typename F>
2827 inline auto series_merge_f(S1 &&s1, S2 &&s2,
const F &f) -> decltype(f(std::forward<S1>(s1), std::forward<S2>(s2)))
2829 if (s1.get_symbol_set() == s2.get_symbol_set()) {
2831 return f(std::forward<S1>(s1), std::forward<S2>(s2));
2834 const auto merge =
ss_merge(s1.get_symbol_set(), s2.get_symbol_set());
2837 static_assert(std::is_same<decltype(f(std::forward<S1>(s1), std::forward<S2>(s2))),
2838 decltype(f(s1.merge_arguments(std::get<0>(merge), std::get<1>(merge)),
2839 std::forward<S2>(s2)))>::value,
2840 "Inconsistent return type.");
2841 static_assert(std::is_same<decltype(f(std::forward<S1>(s1), std::forward<S2>(s2))),
2842 decltype(f(std::forward<S1>(s1),
2843 s2.merge_arguments(std::get<0>(merge), std::get<2>(merge))))>::value,
2844 "Inconsistent return type.");
2845 static_assert(std::is_same<decltype(f(std::forward<S1>(s1), std::forward<S2>(s2))),
2846 decltype(f(s1.merge_arguments(std::get<0>(merge), std::get<1>(merge)),
2847 s2.merge_arguments(std::get<0>(merge), std::get<2>(merge))))>::value,
2848 "Inconsistent return type.");
2850 const bool s1_needs_copy = (std::get<0>(merge) != s1.get_symbol_set()),
2851 s2_needs_copy = (std::get<0>(merge) != s2.get_symbol_set());
2852 const unsigned mask = unsigned(s1_needs_copy) + (unsigned(s2_needs_copy) << 1u);
2853 piranha_assert(mask != 0u);
2857 return f(s1.merge_arguments(std::get<0>(merge), std::get<1>(merge)), std::forward<S2>(s2));
2859 return f(std::forward<S1>(s1), s2.merge_arguments(std::get<0>(merge), std::get<2>(merge)));
2862 return f(s1.merge_arguments(std::get<0>(merge), std::get<1>(merge)),
2863 s2.merge_arguments(std::get<0>(merge), std::get<2>(merge)));
2871 template <
typename Series>
2885 if (s.size() > 1u) {
2889 if (s.size() > 1u) {
2899 template <
typename Series>
2913 if (s.size() > 1u) {
2917 if (s.size() > 1u) {
2930 template <
typename T>
2938 template <
typename U>
2950 template <
typename Series>
2965 inline namespace impl
2969 template <
typename Series,
typename T>
2970 using series_pow_member_t = decltype(std::declval<const Series &>().pow(std::declval<const T &>()));
2972 template <
typename Series,
typename T>
2973 using pow_series_enabler
2974 = enable_if_t<conjunction<is_series<Series>, is_detected<series_pow_member_t, Series, T>>::value>;
2985 template <
typename Series,
typename T>
2986 struct pow_impl<Series, T, pow_series_enabler<Series, T>> {
2988 using pow_type = series_pow_member_t<Series, T>;
3017 template <
typename T>
3018 class series_has_invert : sfinae_types
3020 template <
typename U>
3021 static auto test(
const U &t) -> decltype(t.invert(), void(), yes());
3022 static no test(...);
3025 static const bool value = std::is_same<decltype(test(std::declval<T>())), yes>::value;
3029 template <typename T, typename std::enable_if<is_series<T>::value && series_has_invert<T>::value,
int>::type = 0>
3030 inline auto series_invert_impl(
const T &s) -> decltype(s.invert())
3035 struct series_cf_invert_functor {
3036 template <
typename T>
3037 auto operator()(
const T &x)
const -> decltype(
math::invert(x))
3041 static constexpr
const char *name =
"inverse";
3053 template <
typename Cf,
typename Key,
typename Derived,
3054 typename std::enable_if<
3057 typename Derived::term_type::cf_type,
3058 decltype(
math::invert(std::declval<const typename Derived::term_type::cf_type &>()))>::value,
3061 inline Derived series_invert_impl(
const series<Cf, Key, Derived> &s)
3063 return apply_cf_functor<series_cf_invert_functor, Derived>(s);
3068 template <
typename Cf,
typename Key,
typename Derived,
3069 typename std::enable_if<
3072 typename Derived::term_type::cf_type,
3073 decltype(
math::invert(std::declval<const typename Derived::term_type::cf_type &>()))>::value,
3076 inline series_rebind<Derived, decltype(math::invert(std::declval<const typename Derived::term_type::cf_type &>()))>
3077 series_invert_impl(
const series<Cf, Key, Derived> &s)
3080 = series_rebind<Derived, decltype(math::invert(std::declval<const typename Derived::term_type::cf_type &>()))>;
3081 return apply_cf_functor<series_cf_invert_functor, ret_type>(s);
3085 template <
typename T>
3086 using series_invert_enabler =
3087 typename std::enable_if<true_tt<decltype(series_invert_impl(std::declval<const T &>()))>::value>::type;
3100 template <
typename Series>
3113 template <
typename T>
3114 auto operator()(
const T &s)
const -> decltype(detail::series_invert_impl(s))
3116 return detail::series_invert_impl(s);
3125 template <
typename T>
3126 class series_has_sin : sfinae_types
3128 template <
typename U>
3129 static auto test(
const U &t) -> decltype(t.sin());
3130 static no test(...);
3133 static const bool value = is_returnable<decltype(test(std::declval<T>()))>::value;
3138 template <typename T, typename std::enable_if<is_series<T>::value && series_has_sin<T>::value,
int>::type = 0>
3139 inline auto series_sin_impl(
const T &s) -> decltype(s.sin())
3144 struct series_cf_sin_functor {
3145 template <
typename T>
3146 auto operator()(
const T &x)
const -> decltype(
math::sin(x))
3150 static constexpr
const char *name =
"sine";
3158 typename Cf,
typename Key,
typename Derived,
3159 typename std::enable_if<
3161 && std::is_same<
typename Derived::term_type::cf_type,
3162 decltype(
math::sin(std::declval<const typename Derived::term_type::cf_type &>()))>::value,
3165 inline Derived series_sin_impl(
const series<Cf, Key, Derived> &s)
3167 return apply_cf_functor<series_cf_sin_functor, Derived>(s);
3173 typename Cf,
typename Key,
typename Derived,
3174 typename std::enable_if<
3176 && !std::is_same<
typename Derived::term_type::cf_type,
3177 decltype(
math::sin(std::declval<const typename Derived::term_type::cf_type &>()))>::value,
3180 inline series_rebind<Derived, decltype(math::sin(std::declval<const typename Derived::term_type::cf_type &>()))>
3181 series_sin_impl(
const series<Cf, Key, Derived> &s)
3184 = series_rebind<Derived, decltype(math::sin(std::declval<const typename Derived::term_type::cf_type &>()))>;
3185 return apply_cf_functor<series_cf_sin_functor, ret_type>(s);
3189 template <
typename T>
3190 using series_sin_enabler =
3191 typename std::enable_if<true_tt<decltype(series_sin_impl(std::declval<const T &>()))>::value>::type;
3194 template <
typename T>
3195 class series_has_cos : sfinae_types
3197 template <
typename U>
3198 static auto test(
const U &t) -> decltype(t.cos());
3199 static no test(...);
3202 static const bool value = is_returnable<decltype(test(std::declval<T>()))>::value;
3205 template <typename T, typename std::enable_if<is_series<T>::value && series_has_cos<T>::value,
int>::type = 0>
3206 inline auto series_cos_impl(
const T &s) -> decltype(s.cos())
3211 struct series_cf_cos_functor {
3212 template <
typename T>
3213 auto operator()(
const T &x)
const -> decltype(
math::cos(x))
3217 static constexpr
const char *name =
"cosine";
3221 typename Cf,
typename Key,
typename Derived,
3222 typename std::enable_if<
3224 && std::is_same<
typename Derived::term_type::cf_type,
3225 decltype(
math::cos(std::declval<const typename Derived::term_type::cf_type &>()))>::value,
3228 inline Derived series_cos_impl(
const series<Cf, Key, Derived> &s)
3230 return apply_cf_functor<series_cf_cos_functor, Derived>(s);
3234 typename Cf,
typename Key,
typename Derived,
3235 typename std::enable_if<
3237 && !std::is_same<
typename Derived::term_type::cf_type,
3238 decltype(
math::cos(std::declval<const typename Derived::term_type::cf_type &>()))>::value,
3241 inline series_rebind<Derived, decltype(math::cos(std::declval<const typename Derived::term_type::cf_type &>()))>
3242 series_cos_impl(
const series<Cf, Key, Derived> &s)
3245 = series_rebind<Derived, decltype(math::cos(std::declval<const typename Derived::term_type::cf_type &>()))>;
3246 return apply_cf_functor<series_cf_cos_functor, ret_type>(s);
3249 template <
typename T>
3250 using series_cos_enabler =
3251 typename std::enable_if<true_tt<decltype(series_cos_impl(std::declval<const T &>()))>::value>::type;
3265 template <
typename Series>
3266 struct sin_impl<Series, detail::series_sin_enabler<Series>> {
3279 auto operator()(
const Series &s)
const -> decltype(detail::series_sin_impl(s))
3281 return detail::series_sin_impl(s);
3293 template <
typename Series>
3294 struct cos_impl<Series, detail::series_cos_enabler<Series>> {
3307 auto operator()(
const Series &s)
const -> decltype(detail::series_cos_impl(s))
3309 return detail::series_cos_impl(s);
3318 template <
typename Series>
3319 using series_partial_enabler =
typename std::enable_if<is_series<Series>::value
3320 && is_returnable<decltype(std::declval<const Series &>().partial(
3321 std::declval<const std::string &>()))>::value>::type;
3324 template <
typename Series>
3325 using series_integrate_enabler =
3326 typename std::enable_if<is_series<Series>::value
3327 && is_returnable<decltype(std::declval<const Series &>().integrate(
3328 std::declval<const std::string &>()))>::value>::type;
3339 template <
typename Series>
3358 template <
typename T>
3359 auto operator()(
const T &s,
const std::string &name)
const -> decltype(s.partial(name))
3361 using partial_type = decltype(s.partial(name));
3362 bool custom =
false;
3363 std::function<partial_type(const T &)> func;
3366 std::lock_guard<std::mutex> lock(T::s_cp_mutex);
3367 auto it = s.get_cp_map().find(name);
3368 if (it != s.get_cp_map().end()) {
3376 return s.partial(name);
3385 template <
typename Series>
3396 template <
typename T>
3397 auto operator()(
const T &s,
const std::string &name)
const -> decltype(s.integrate(name))
3399 return s.integrate(name);
3403 inline namespace impl
3408 template <
typename Series,
typename T>
3409 using series_eval_type = decltype(
3411 * std::declval<const typename Series::term_type::key_type &>().
evaluate(std::declval<
const std::vector<T> &>(),
3412 std::declval<const symbol_fset &>()));
3414 template <
typename Series,
typename T>
3415 using math_series_evaluate_enabler
3417 std::is_constructible<series_eval_type<Series, T>,
const int &>,
3419 std::is_copy_constructible<T>>::value>;
3432 template <
typename Series,
typename T>
3435 using eval_type = series_eval_type<Series, T>;
3438 template <typename E, enable_if_t<has_multiply_accumulate<E>::value,
int> = 0>
3439 static void multadd(E &retval,
const E &a,
const E &b)
3443 template <
typename E1,
typename E2,
typename E3>
3444 static void multadd(E1 &retval,
const E2 &a,
const E3 &b)
3476 const auto &ss = s.get_symbol_set();
3480 PIRANHA_MAYBE_TLS std::vector<T> evec;
3484 auto it_dict = dict.begin();
3485 const auto it_dict_f = dict.end();
3486 for (
const auto &sym : ss) {
3489 it_dict = std::lower_bound(
3490 it_dict, it_dict_f, sym,
3491 [](
const std::pair<std::string, T> &p,
const std::string &str) {
return p.first < str; });
3494 if (unlikely(it_dict == it_dict_f || it_dict->first != sym)) {
3496 piranha_throw(std::invalid_argument,
"cannot evaluate series: the symbol '" + sym
3497 +
"' is missing from the series evaluation dictionary'");
3500 evec.push_back(it_dict->second);
3507 piranha_assert(evec.size() == ss.size());
3510 eval_type retval(0);
3511 for (
const auto &t : s._container()) {
3512 multadd(retval,
math::evaluate(t.m_cf, dict), t.m_key.evaluate(evec, ss));
3519 inline namespace impl
3524 template <
typename Archive,
typename Series>
3525 using series_boost_save_enabler = enable_if_t<
3526 conjunction<is_series<Series>, has_boost_save<Archive, decltype(
symbol_fset{}.size())>,
3527 has_boost_save<Archive, const std::string &>,
3528 has_boost_save<Archive, decltype(std::declval<const Series &>().size())>,
3529 has_boost_save<Archive, typename Series::term_type::cf_type>,
3530 has_boost_save<Archive, boost_s11n_key_wrapper<typename Series::term_type::key_type>>>::value>;
3533 template <
typename Archive,
typename Series>
3534 using series_boost_load_enabler = enable_if_t<conjunction<
3535 is_series<Series>, has_boost_load<Archive, decltype(
symbol_fset{}.size())>, has_boost_load<Archive, std::string>,
3536 has_boost_load<Archive, decltype(std::declval<const Series &>().size())>,
3537 has_boost_load<Archive, typename Series::term_type::cf_type>,
3538 has_boost_load<Archive, boost_s11n_key_wrapper<typename Series::term_type::key_type>>>::value>;
3552 template <
typename Archive,
typename Series>
3576 template <
typename Archive,
typename Series>
3581 #if defined(PIRANHA_WITH_MSGPACK) 3583 inline namespace impl
3587 template <
typename Stream,
typename Series>
3588 using series_msgpack_pack_enabler
3591 has_safe_cast<std::uint32_t, typename Series::size_type>,
3592 has_msgpack_pack<Stream, typename Series::term_type::cf_type>,
3593 key_has_msgpack_pack<Stream, typename Series::term_type::key_type>>::value>;
3595 template <
typename Series>
3596 using series_msgpack_convert_enabler
3597 = enable_if_t<conjunction<is_series<Series>, has_msgpack_convert<std::string>,
3598 has_msgpack_convert<typename Series::term_type::cf_type>,
3599 key_has_msgpack_convert<typename Series::term_type::key_type>>::value>;
3612 template <
typename Stream,
typename Series>
3635 packer.pack_array(2u);
3637 const auto &ss = s.get_symbol_set();
3638 packer.pack_array(safe_cast<std::uint32_t>(ss.size()));
3639 for (
const auto &sym : ss) {
3643 packer.pack_array(safe_cast<std::uint32_t>(s.size()));
3644 for (
const auto &t : s._container()) {
3646 packer.pack_array(2u);
3648 t.m_key.msgpack_pack(packer, f, ss);
3661 template <
typename Series>
3686 using term_type =
typename Series::term_type;
3687 using cf_type =
typename term_type::cf_type;
3688 using key_type =
typename term_type::key_type;
3689 using s_size_t = decltype(s.size());
3693 std::array<std::vector<msgpack::object>, 2> tmp_v;
3696 std::vector<std::string> v_str;
3697 std::transform(tmp_v[0].begin(), tmp_v[0].end(), std::back_inserter(v_str),
3698 [f](
const msgpack::object &obj) -> std::string {
3699 std::string tmp_str;
3703 s.set_symbol_set(
symbol_fset(v_str.begin(), v_str.end()));
3705 s._container().rehash(boost::numeric_cast<s_size_t>(
3706 std::ceil(static_cast<double>(tmp_v[1].size()) / s._container().max_load_factor())));
3708 for (
const auto &t : tmp_v[1]) {
3709 std::array<msgpack::object, 2> tmp_term;
3710 t.convert(tmp_term);
3714 tmp_key.msgpack_convert(tmp_term[1], f, s.get_symbol_set());
3715 s.insert(term_type{std::move(tmp_cf), std::move(tmp_key)});
3722 inline namespace impl
3725 template <
typename T>
3726 using series_zero_is_absorbing_enabler = enable_if_t<is_series<uncvref_t<T>>::value>;
3737 template <
typename T>
3745 static const bool value = implementation_defined;
3748 template <
typename T>
size_type size() const
Series size.
math_pow_t< T, U > pow(const T &x, const U &y)
Exponentiation.
auto invert(const T &x) -> decltype(invert_impl< T >()(x))
Compute the inverse.
auto print_tex_coefficient(std::ostream &os, const T &cf) -> decltype(print_tex_coefficient_impl< T >()(os, cf))
Print series coefficient in TeX mode.
Cf m_cf
Coefficient member.
auto operator()(const T &s, const std::string &name) const -> decltype(s.integrate(name))
Call operator.
Derived transform(std::function< std::pair< typename term_type::cf_type, Derived >(const std::pair< typename term_type::cf_type, Derived > &)> func) const
Term transformation.
bool operator()(const Series &s) const
Call operator.
void boost_load(Archive &ar, T &x)
Load from Boost archive.
Default functor for the implementation of piranha::math::negate().
Multiprecision integer class.
friend bool operator!=(const T &x, const U &... y)
Inequality operator involving piranha::series.
Default implementation of piranha::boost_load().
friend T & operator*=(T &x, U &&... y)
In-place multiplication involving piranha::series.
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.
detail::math_partial_type< T > partial(const T &x, const std::string &str)
Partial derivative.
Derived trim() const
Trim.
auto operator()(const Series &s) const -> decltype(detail::series_sin_impl(s))
Call operator.
Default functor for the implementation of piranha::math::integrate().
friend T & operator-=(T &x, U &&... y)
In-place subtraction involving piranha::series.
Type trait to detect the availability of a series multiplier.
static const bool value
Value of the type trait.
Default functor for the implementation of piranha::math::is_zero().
Implementation of piranha::boost_load() via the Boost API.
boost::container::flat_map< std::string, T > symbol_fmap
Flat map of symbols.
series_rebind_implementation< T, Cf > series_rebind
Rebind series.
In-place addable type trait.
detail::math_cos_type< T > cos(const T &x)
Cosine.
Default functor for the implementation of piranha::math::sin().
sparsity_info_type table_sparsity() const
Table sparsity.
const_iterator end() const
Const end iterator.
Default implementation of piranha::boost_save().
static void register_custom_derivative(const std::string &name, F func)
Register custom partial derivative.
void negate(T &x)
In-place negation.
void operator()(std::ostream &os, const Series &s) const
Call operator.
Default functor for the implementation of piranha::math::cos().
Default functor for the implementation of piranha::math::evaluate().
pow_type operator()(const Series &s, const T &x) const
Call operator.
bool is_single_coefficient() const
Test for single-coefficient series.
Default functor for the implementation of piranha::math::pow().
static void clear_pow_cache()
Clear the internal cache of natural powers.
Type trait to detect the presence of the piranha::math::is_zero() function.
void operator()(std::ostream &os, const Series &s) const
Call operator.
static void unregister_all_custom_derivatives()
Unregister all custom partial derivatives.
series & operator=(const T &x)
Generic assignment operator.
static unsigned long get_max_term_output()
Get max term output.
Derived operator-() const
Negation operator.
partial_type< Series > partial(const std::string &name) const
Partial derivative.
std::tuple< symbol_fset, symbol_idx_fmap< symbol_fset >, symbol_idx_fmap< symbol_fset > > ss_merge(const symbol_fset &s1, const symbol_fset &s2)
Merge two symbol_fset.
bool is_identical(const Derived &other) const
Check for identical series.
pow_ret_type< T, U > pow(const T &x) const
Exponentiation.
math_evaluate_t< T, U > evaluate(const T &x, const symbol_fmap< U > &dict)
Evaluation.
Default functor for the implementation of piranha::msgpack_convert().
Derived operator+() const
Identity operator.
const_iterator_impl const_iterator
Const iterator.
#define piranha_throw(exception_type,...)
Exception-throwing macro.
boost::container::flat_set< std::string > symbol_fset
Flat set of symbols.
friend binary_mul_type< T, U... > operator*(T &&x, U &&... y)
Binary multiplication involving piranha::series.
void operator()(U &s) const
Call operator.
Key key_type
Alias for the key type.
static void unregister_custom_derivative(const std::string &name)
Unregister custom partial derivative.
~series()
Trivial destructor.
Derived filter(std::function< bool(const std::pair< typename term_type::cf_type, Derived > &)> func) const
Term filtering.
Default functor for the implementation of piranha::msgpack_pack().
typename container_type::size_type size_type
Size type.
msgpack_format
Serialization format for msgpack.
std::size_t hash() const
Hash value.
Detect if zero is a multiplicative absorber.
Default functor for the implementation of piranha::math::partial().
const_iterator begin() const
Const begin iterator.
Detect if type can be returned from a function.
friend binary_div_type< T, U... > operator/(T &&x, U &&... y)
Binary division involving piranha::series.
bool is_compatible(const symbol_fset &args) const noexcept
Compatibility test.
Cf cf_type
Alias for the coefficient type.
symbol_fset::size_type symbol_idx
Symbol index.
const container_type & _container() const
Get a const reference to the container of terms.
symbol_idx ss_index_of(const symbol_fset &ref, const std::string &name)
Identify the index of a symbol in a symbol_fset.
symbol_fset ss_trim(const symbol_fset &s, const std::vector< char > &mask)
Trim a symbol_fset.
bool is_zero(const T &x)
Zero test.
friend binary_sub_type< T, U... > operator-(T &&x, U &&... y)
Binary subtraction involving piranha::series.
const_iterator begin() const
Begin iterator.
container_type & _container()
Get a mutable reference to the container of terms.
Implementation of piranha::boost_save() via the Boost API.
bool empty() const
Empty test.
double table_load_factor() const
Table load factor.
void msgpack_pack(msgpack::packer< Stream > &packer, const T &x, msgpack_format f)
Pack generic object in a msgpack stream.
Detect the presence of piranha::msgpack_pack().
friend T & operator/=(T &x, U &&... y)
In-place division involving piranha::series.
const symbol_fset & get_symbol_set() const
Symbol set getter.
void multiply_accumulate(T &x, const T &y, const T &z)
Multiply-accumulate.
static const bool value
Value of the type trait.
std::size_t size_type
Size type.
const_iterator end() const
End iterator.
series & operator=(const series &other)
Copy-assignment operator.
friend T & operator+=(T &x, U &&... y)
In-place addition involving piranha::series.
void negate()
Negate series in-place.
auto operator()(const Series &s) const -> decltype(detail::series_cos_impl(s))
Call operator.
void operator()(msgpack::packer< Stream > &packer, const Series &s, msgpack_format f) const
Call operator.
eval_type operator()(const Series &s, const symbol_fmap< T > &dict) const
Call operator.
void insert(T &&term)
Insert term.
auto operator()(const T &s) const -> decltype(detail::series_invert_impl(s))
Call operator.
static const bool value
Value of the type trait.
friend std::ostream & operator<<(std::ostream &os, const series &s)
Overloaded stream operator for piranha::series.
auto operator()(const T &s, const std::string &name) const -> decltype(s.partial(name))
Call operator.
Type trait to detect piranha::safe_cast().
auto print_coefficient(std::ostream &os, const T &cf) -> decltype(print_coefficient_impl< T >()(os, cf))
Print series coefficient.
void boost_save(Archive &ar, const T &x)
Save to Boost archive.
series(const T &x)
Generic constructor.
Default functor for the implementation of piranha::math::invert().
void set_symbol_set(const symbol_fset &args)
Symbol set setter.
symbol_fset m_symbol_set
Symbol set.
friend bool operator==(const T &x, const U &... y)
Equality operator involving piranha::series.
size_type table_bucket_count() const
Table bucket count.
container_type m_container
Terms container.
void insert(T &&term)
Insert generic term with Sign = true.
Default functor for piranha::print_tex_coefficient().
static const bool value
Value of the type trait.
Type trait for well-behaved container elements.
#define PIRANHA_TT_CHECK(tt,...)
Macro for static type trait checks.
static const bool value
Value of the type trait.
Type trait to detect series types.
friend binary_add_type< T, U... > operator+(T &&x, U &&... y)
Binary addition involving piranha::series.
Check if a series can be rebound.
Default functor for piranha::print_coefficient().
Exception to signal failure in piranha::safe_cast().
detail::math_sin_type< T > sin(const T &x)
Sine.
void print_tex(std::ostream &os) const
Print in TeX mode.
bool is_zero(const symbol_fset &args) const noexcept
Zero test.
void operator()(Series &s, const msgpack::object &o, msgpack_format f) const
Call operator.
safe_cast_type< To, From > safe_cast(const From &x)
Safe cast.
static const std::size_t value
Value of the recursion index.
static const bool value
Value of the type trait.