29 #ifndef PIRANHA_POWER_SERIES_HPP 30 #define PIRANHA_POWER_SERIES_HPP 33 #include <type_traits> 36 #include <piranha/detail/safe_integral_adder.hpp> 38 #include <piranha/math.hpp> 39 #include <piranha/safe_cast.hpp> 40 #include <piranha/series.hpp> 41 #include <piranha/symbol_utils.hpp> 51 struct power_series_tag {
56 struct ps_term_score {
57 typedef typename T::cf_type cf_type;
58 typedef typename T::key_type key_type;
59 static const unsigned value
66 using common_degree_type_checks
67 = conjunction<std::is_constructible<T, const int &>, is_less_than_comparable<T>, is_container_element<T>>;
70 #define PIRANHA_DEFINE_PS_PROPERTY_GETTER(property) \ 71 template <typename Term, enable_if_t<ps_term_score<Term>::value == 1u, int> = 0> \ 72 inline auto ps_get_##property(const Term &t, const symbol_fset &)->decltype(math::property(t.m_cf)) \ 74 return math::property(t.m_cf); \ 76 template <typename Term, enable_if_t<ps_term_score<Term>::value == 2u, int> = 0> \ 77 inline auto ps_get_##property(const Term &t, const symbol_fset &s)->decltype(t.m_key.property(s)) \ 79 return t.m_key.property(s); \ 83 enable_if_t<ps_term_score<Term>::value == 3u \ 84 && conjunction<std::is_integral<decltype(math::property(std::declval<const Term &>().m_cf))>, \ 85 std::is_integral<decltype(std::declval<const Term &>().m_key.property( \ 86 std::declval<const symbol_fset &>()))>>::value, \ 88 inline auto ps_get_##property(const Term &t, const symbol_fset &s) \ 89 ->decltype(math::property(t.m_cf) + t.m_key.property(s)) \ 91 using ret_type = decltype(math::property(t.m_cf) + t.m_key.property(s)); \ 92 ret_type retval(math::property(t.m_cf)); \ 93 detail::safe_integral_adder(retval, static_cast<ret_type>(t.m_key.property(s))); \ 96 template <typename Term, \ 98 ps_term_score<Term>::value == 3u \ 100 negation<std::is_integral<decltype(math::property(std::declval<const Term &>().m_cf))>>, \ 101 negation<std::is_integral<decltype(std::declval<const Term &>().m_key.property( \ 102 std::declval<const symbol_fset &>()))>>>::value, \ 104 inline auto ps_get_##property(const Term &t, const symbol_fset &s) \ 105 ->decltype(math::property(t.m_cf) + t.m_key.property(s)) \ 107 return math::property(t.m_cf) + t.m_key.property(s); \ 109 template <typename T> \ 110 using ps_##property##_type_ = decltype( \ 111 ps_get_##property(std::declval<const typename T::term_type &>(), std::declval<const symbol_fset &>())); \ 112 template <typename T> \ 113 using ps_##property##_type \ 114 = enable_if_t<common_degree_type_checks<ps_##property##_type_<T>>::value, ps_##property##_type_<T>>; 115 PIRANHA_DEFINE_PS_PROPERTY_GETTER(degree)
116 PIRANHA_DEFINE_PS_PROPERTY_GETTER(ldegree)
117 #undef PIRANHA_DEFINE_PS_PROPERTY_GETTER 120 #define PIRANHA_DEFINE_PARTIAL_PS_PROPERTY_GETTER(property) \ 121 template <typename Term, enable_if_t<ps_term_score<Term>::value == 1u, int> = 0> \ 122 inline auto ps_get_##property(const Term &t, const symbol_fset &names, const symbol_idx_fset &, \ 123 const symbol_fset &) \ 124 ->decltype(math::property(t.m_cf, names)) \ 126 return math::property(t.m_cf, names); \ 128 template <typename Term, enable_if_t<ps_term_score<Term>::value == 2u, int> = 0> \ 129 inline auto ps_get_##property(const Term &t, const symbol_fset &, const symbol_idx_fset &p, const symbol_fset &s) \ 130 ->decltype(t.m_key.property(p, s)) \ 132 return t.m_key.property(p, s); \ 136 enable_if_t<ps_term_score<Term>::value == 3u \ 137 && conjunction<std::is_integral<decltype(math::property( \ 138 std::declval<const Term &>().m_cf, std::declval<const symbol_fset &>()))>, \ 139 std::is_integral<decltype(std::declval<const Term &>().m_key.property( \ 140 std::declval<const symbol_idx_fset &>(), \ 141 std::declval<const symbol_fset &>()))>>::value, \ 143 inline auto ps_get_##property(const Term &t, const symbol_fset &names, const symbol_idx_fset &p, \ 144 const symbol_fset &s) \ 145 ->decltype(math::property(t.m_cf, names) + t.m_key.property(p, s)) \ 147 using ret_type = decltype(math::property(t.m_cf, names) + t.m_key.property(p, s)); \ 148 ret_type retval(math::property(t.m_cf, names)); \ 149 detail::safe_integral_adder(retval, static_cast<ret_type>(t.m_key.property(p, s))); \ 154 enable_if_t<ps_term_score<Term>::value == 3u \ 155 && disjunction<negation<std::is_integral<decltype(math::property( \ 156 std::declval<const Term &>().m_cf, std::declval<const symbol_fset &>()))>>, \ 157 negation<std::is_integral<decltype(std::declval<const Term &>().m_key.property( \ 158 std::declval<const symbol_idx_fset &>(), \ 159 std::declval<const symbol_fset &>()))>>>::value, \ 161 inline auto ps_get_##property(const Term &t, const symbol_fset &names, const symbol_idx_fset &p, \ 162 const symbol_fset &s) \ 163 ->decltype(math::property(t.m_cf, names) + t.m_key.property(p, s)) \ 165 return math::property(t.m_cf, names) + t.m_key.property(p, s); \ 167 template <typename T> \ 168 using ps_p##property##_type_ = decltype( \ 169 ps_get_##property(std::declval<const typename T::term_type &>(), std::declval<const symbol_fset &>(), \ 170 std::declval<const symbol_idx_fset &>(), std::declval<const symbol_fset &>())); \ 171 template <typename T> \ 172 using ps_p##property##_type \ 173 = enable_if_t<common_degree_type_checks<ps_p##property##_type_<T>>::value, ps_p##property##_type_<T>>; 174 PIRANHA_DEFINE_PARTIAL_PS_PROPERTY_GETTER(degree)
175 PIRANHA_DEFINE_PARTIAL_PS_PROPERTY_GETTER(ldegree)
176 #undef PIRANHA_DEFINE_PARTIAL_PS_PROPERTY_GETTER 180 template <
typename Term,
typename T,
181 enable_if_t<has_truncate_degree<typename Term::cf_type, T>::value && (ps_term_score<Term>::value >> 1u) == 0u,
183 inline std::pair<bool, Term> ps_truncate_term(
const Term &t,
const T &max_degree,
const symbol_fset &)
191 template <
typename Term,
typename T,
193 (ps_term_score<Term>::value >> 1u) == 1u
194 && conjunction<negation<has_truncate_degree<typename Term::cf_type, T>>,
195 is_greater_than_comparable<decltype(std::declval<const typename Term::key_type &>()
196 .ldegree(std::declval<const symbol_fset &>())),
199 inline std::pair<bool, Term> ps_truncate_term(
const Term &t,
const T &max_degree,
const symbol_fset &s)
201 if (t.m_key.ldegree(s) > max_degree) {
203 return std::make_pair(
false, Term());
206 return std::make_pair(
true, Term(t.m_cf, t.m_key));
214 template <
typename Term,
typename T,
215 enable_if_t<has_truncate_degree<
typename Term::cf_type,
216 decltype(std::declval<const T &>()
217 - std::declval<const typename Term::key_type &>().
ldegree(
218 std::declval<const symbol_fset &>()))>::value
219 && (ps_term_score<Term>::value >> 1u) == 1u,
221 inline std::pair<bool, Term> ps_truncate_term(
const Term &t,
const T &max_degree,
const symbol_fset &s)
225 return std::make_pair(
true, Term(
math::truncate_degree(t.m_cf, max_degree - t.m_key.ldegree(s)), t.m_key));
230 template <
typename Term,
typename T,
231 enable_if_t<has_truncate_degree<typename Term::cf_type, T>::value && (ps_term_score<Term>::value >> 1u) == 0u,
233 inline std::pair<bool, Term> ps_truncate_term(
const Term &t,
const T &max_degree,
const symbol_fset &names,
240 template <
typename Term,
typename T,
242 (ps_term_score<Term>::value >> 1u) == 1u
243 && conjunction<negation<has_truncate_degree<typename Term::cf_type, T>>,
244 is_greater_than_comparable<
245 decltype(std::declval<const typename Term::key_type &>().ldegree(
246 std::declval<const symbol_idx_fset &>(), std::declval<const symbol_fset &>())),
249 inline std::pair<bool, Term> ps_truncate_term(
const Term &t,
const T &max_degree,
const symbol_fset &,
252 if (t.m_key.ldegree(p, s) > max_degree) {
253 return std::make_pair(
false, Term());
255 return std::make_pair(
true, Term(t.m_cf, t.m_key));
261 template <
typename Term,
typename T,
262 enable_if_t<has_truncate_degree<
typename Term::cf_type,
263 decltype(std::declval<const T &>()
264 - std::declval<const typename Term::key_type &>().
ldegree(
265 std::declval<const symbol_idx_fset &>(),
266 std::declval<const symbol_fset &>()))>::value
267 && (ps_term_score<Term>::value >> 1u) == 1u,
269 inline std::pair<bool, Term> ps_truncate_term(
const Term &t,
const T &max_degree,
const symbol_fset &names,
272 return std::make_pair(
true,
313 template <
typename Series,
typename Derived>
319 template <
typename T>
320 using t_truncate_term_t
321 = decltype(ps_truncate_term(std::declval<const typename base::term_type &>(), std::declval<const T &>(),
322 std::declval<const symbol_fset &>()));
323 template <
typename T>
324 using truncate_degree_enabler = enable_if_t<is_detected<t_truncate_term_t, T>::value,
int>;
326 template <
typename T>
327 using p_truncate_term_t
328 = decltype(ps_truncate_term(std::declval<const typename base::term_type &>(), std::declval<const T &>(),
329 std::declval<const symbol_fset &>(), std::declval<const symbol_idx_fset &>(),
330 std::declval<const symbol_fset &>()));
331 template <
typename T>
332 using truncate_pdegree_enabler = enable_if_t<is_detected<p_truncate_term_t, T>::value,
int>;
334 template <
typename T>
335 using degree_type = ps_degree_type<T>;
336 template <
typename T>
337 using ldegree_type = ps_ldegree_type<T>;
338 template <
typename T>
339 using pdegree_type = ps_pdegree_type<T>;
340 template <
typename T>
341 using pldegree_type = ps_pldegree_type<T>;
372 PIRANHA_TT_CHECK(std::is_base_of,
power_series, Derived);
389 template <
typename T = power_series>
393 auto it = std::max_element(
394 this->m_container.begin(), this->m_container.end(), [
this](
const term_type &t1,
const term_type &t2) {
395 return ps_get_degree(t1, this->m_symbol_set) < ps_get_degree(t2, this->m_symbol_set);
397 return (it == this->m_container.end()) ? degree_type<T>(0) : ps_get_degree(*it, this->m_symbol_set);
415 template <
typename T = power_series>
419 auto it = std::min_element(
420 this->m_container.begin(), this->m_container.end(), [
this](
const term_type &t1,
const term_type &t2) {
421 return ps_get_ldegree(t1, this->m_symbol_set) < ps_get_ldegree(t2, this->m_symbol_set);
423 return (it == this->m_container.end()) ? ldegree_type<T>(0) : ps_get_ldegree(*it, this->m_symbol_set);
443 template <
typename T = power_series>
448 auto it = std::max_element(this->m_container.begin(), this->m_container.end(),
450 return ps_get_degree(t1, names, idx, this->m_symbol_set)
451 < ps_get_degree(t2, names, idx, this->m_symbol_set);
453 return (it == this->m_container.end()) ? pdegree_type<T>(0)
454 : ps_get_degree(*it, names, idx, this->m_symbol_set);
474 template <
typename T = power_series>
479 auto it = std::min_element(this->m_container.begin(), this->m_container.end(),
481 return ps_get_ldegree(t1, names, idx, this->m_symbol_set)
482 < ps_get_ldegree(t2, names, idx, this->m_symbol_set);
484 return (it == this->m_container.end()) ? pldegree_type<T>(0)
485 : ps_get_ldegree(*it, names, idx, this->m_symbol_set);
509 template <
typename T, truncate_degree_enabler<T> = 0>
513 retval.m_symbol_set = this->m_symbol_set;
514 const auto it_f = this->m_container.end();
515 for (
auto it = this->m_container.begin(); it != it_f; ++it) {
516 auto tmp = ps_truncate_term(*it, max_degree, retval.m_symbol_set);
518 retval.insert(std::move(tmp.second));
542 template <
typename T, truncate_pdegree_enabler<T> = 0>
546 retval.m_symbol_set = this->m_symbol_set;
548 const auto it_f = this->m_container.end();
549 for (
auto it = this->m_container.begin(); it != it_f; ++it) {
550 auto tmp = ps_truncate_term(*it, max_degree, names, idx, retval.m_symbol_set);
552 retval.insert(std::move(tmp.second));
559 inline namespace impl
563 template <
typename Series>
564 using ps_degree_enabler = enable_if_t<std::is_base_of<power_series_tag, Series>::value>;
575 template <
typename Series>
588 template <
typename... Args>
589 auto operator()(
const Series &s,
const Args &... args)
const -> decltype(s.degree(args...))
591 return s.degree(args...);
600 template <
typename Series>
613 template <
typename... Args>
614 auto operator()(
const Series &s,
const Args &... args)
const -> decltype(s.ldegree(args...))
616 return s.ldegree(args...);
625 template <
typename Series,
typename T>
639 template <
typename... Args>
640 auto operator()(
const Series &s,
const T &max_degree,
const Args &... args)
const 641 -> decltype(s.truncate_degree(max_degree, args...))
643 return s.truncate_degree(max_degree, args...);
static const bool value
Value of the type trait.
static const bool value
Value of the type trait.
Default functor for the implementation of piranha::math::ldegree().
symbol_idx_fset ss_intersect_idx(const symbol_fset &s1, const symbol_fset &s2)
Find the indices of the intersection of two symbol_fset.
~power_series()
Trivial destructor.
ldegree_type< T > ldegree() const
Total low degree.
#define PIRANHA_FORWARDING_CTOR(Derived, Base)
Constructor-forwarding macro.
pdegree_type< T > degree(const symbol_fset &names) const
Partial degree.
Implementation of the piranha::math::truncate_degree() functor.
static const bool value
Value of the type trait.
boost::container::flat_set< std::string > symbol_fset
Flat set of symbols.
power_series & operator=(const power_series &other)=default
Copy assignment operator.
auto operator()(const Series &s, const Args &... args) const -> decltype(s.ldegree(args...))
Call operator.
Derived truncate_degree(const T &max_degree, const symbol_fset &names) const
Partial degree truncation.
T truncate_degree(const T &x, const U &max_degree)
Truncation based on the total degree.
pldegree_type< T > ldegree(const symbol_fset &names) const
Partial low degree.
auto operator()(const Series &s, const Args &... args) const -> decltype(s.degree(args...))
Call operator.
auto ldegree(const T &x) -> decltype(ldegree_impl< T >()(x))
Total low degree.
static const bool value
Value of the type trait.
Default functor for the implementation of piranha::math::degree().
boost::container::flat_set< symbol_idx > symbol_idx_fset
Flat set of symbol indices.
power_series()=default
Defaulted default constructor.
auto operator()(const Series &s, const T &max_degree, const Args &... args) const -> decltype(s.truncate_degree(max_degree, args...))
Call operator.
Type trait to detect series types.
Derived truncate_degree(const T &max_degree) const
Total degree truncation.
#define PIRANHA_FORWARDING_ASSIGNMENT(Derived, Base)
Assignment-forwarding macro.
degree_type< T > degree() const
Total degree.