29 #ifndef PIRANHA_POISSON_SERIES_HPP 30 #define PIRANHA_POISSON_SERIES_HPP 34 #include <boost/container/container_fwd.hpp> 35 #include <boost/iterator/transform_iterator.hpp> 39 #include <type_traits> 43 #include <piranha/base_series_multiplier.hpp> 44 #include <piranha/config.hpp> 45 #include <piranha/detail/divisor_series_fwd.hpp> 46 #include <piranha/detail/poisson_series_fwd.hpp> 47 #include <piranha/detail/polynomial_fwd.hpp> 48 #include <piranha/detail/sfinae_types.hpp> 51 #include <piranha/ipow_substitutable_series.hpp> 52 #include <piranha/is_cf.hpp> 53 #include <piranha/key_is_multipliable.hpp> 54 #include <piranha/math.hpp> 55 #include <piranha/mp_integer.hpp> 56 #include <piranha/power_series.hpp> 57 #include <piranha/real_trigonometric_kronecker_monomial.hpp> 58 #include <piranha/safe_cast.hpp> 59 #include <piranha/series.hpp> 60 #include <piranha/series_multiplier.hpp> 61 #include <piranha/substitutable_series.hpp> 62 #include <piranha/symbol_utils.hpp> 63 #include <piranha/t_substitutable_series.hpp> 64 #include <piranha/term.hpp> 65 #include <piranha/thread_pool.hpp> 66 #include <piranha/trigonometric_series.hpp> 75 struct poisson_series_tag {
106 template <
typename Cf>
108 :
public power_series<
109 ipow_substitutable_series<
110 substitutable_series<
111 t_substitutable_series<trigonometric_series<series<Cf, rtk_monomial, poisson_series<Cf>>>,
116 detail::poisson_series_tag
118 #if !defined(PIRANHA_DOXYGEN_INVOKED) 122 trigonometric_series<series<Cf, rtk_monomial, poisson_series<Cf>>>,
129 template <
typename T>
130 using sin_type = decltype(
math::sin(std::declval<const typename T::base &>()));
131 template <
typename T>
132 using cos_type = decltype(
math::cos(std::declval<const typename T::base &>()));
135 template <typename T = poisson_series, typename std::enable_if<!detail::poly_in_cf<T>::value,
int>::type = 0>
136 sin_type<T> sin_impl()
const 138 return math::sin(*static_cast<const base *>(
this));
143 template <typename T = poisson_series, typename std::enable_if<detail::poly_in_cf<T>::value,
int>::type = 0>
144 sin_type<T> sin_impl()
const 146 return special_sin_cos<false, sin_type<T>>(*this);
149 template <typename T = poisson_series, typename std::enable_if<!detail::poly_in_cf<T>::value,
int>::type = 0>
150 cos_type<T> cos_impl()
const 152 return math::cos(*static_cast<const base *>(
this));
154 template <typename T = poisson_series, typename std::enable_if<detail::poly_in_cf<T>::value,
int>::type = 0>
155 cos_type<T> cos_impl()
const 157 return special_sin_cos<true, cos_type<T>>(*this);
162 template <
typename T>
163 static cos_type<T> special_sin_cos_failure(
const T &s,
const std::true_type &)
165 return math::cos(static_cast<const typename T::base &>(s));
167 template <
typename T>
168 static sin_type<T> special_sin_cos_failure(
const T &s,
const std::false_type &)
170 return math::sin(static_cast<const typename T::base &>(s));
175 template <
bool IsCos,
typename RetT,
typename Poly>
176 static RetT poly_to_ps(
const Poly &poly)
179 typedef typename RetT::term_type
term_type;
182 typedef typename key_type::value_type value_type;
184 auto lc = poly.integral_combination();
186 bool sign_change =
false;
187 if (!lc.empty() && lc.begin()->second.sgn() < 0) {
188 std::for_each(lc.begin(), lc.end(), [](std::pair<const std::string, integer> &p) { p.second.neg(); });
196 const std::string &operator()(
const typename decltype(lc)::value_type &p)
const 201 retval.set_symbol_set(
symbol_fset(boost::container::ordered_unique_range_t{},
202 boost::make_transform_iterator(lc.begin(), t_iter{}),
203 boost::make_transform_iterator(lc.end(), t_iter{})));
204 piranha_assert(retval.get_symbol_set().size() == lc.size());
205 std::vector<value_type> v;
206 std::transform(lc.begin(), lc.end(), std::back_inserter(v), [](
const typename decltype(lc)::value_type &p) {
211 return static_cast<value_type
>(p.second);
214 term_type term(cf_type(1), key_type(v.begin(), v.end()));
216 term.m_key.set_flavour(
false);
222 retval.insert(std::move(term));
226 template <
bool IsCos,
typename RetT,
typename T,
227 typename std::enable_if<std::is_base_of<detail::polynomial_tag, typename T::term_type::cf_type>::value,
230 RetT special_sin_cos(
const T &s)
const 233 if (s.is_single_coefficient() && !s.empty()) {
235 return poly_to_ps<IsCos, RetT>(s._container().begin()->m_cf);
236 }
catch (
const std::invalid_argument &) {
241 return special_sin_cos_failure(*
this, std::integral_constant<bool, IsCos>{});
245 template <
bool IsCos,
typename RetT,
typename T,
246 typename std::enable_if<!std::is_base_of<detail::polynomial_tag, typename T::term_type::cf_type>::value,
249 RetT special_sin_cos(
const T &s)
const 251 if (s.is_single_coefficient() && !s.empty()) {
252 return special_sin_cos<IsCos, RetT>(s._container().begin()->m_cf);
254 return special_sin_cos_failure(*
this, std::integral_constant<bool, IsCos>{});
258 template <
typename T>
259 using key_integrate_type
260 = decltype(std::declval<const typename T::term_type::key_type &>()
261 .
integrate(std::declval<const std::string &>(), std::declval<const symbol_fset &>())
267 template <
typename T,
typename ResT,
typename =
void>
268 struct basic_integrate_requirements {
269 static const bool value =
false;
271 template <
typename T,
typename ResT>
272 struct basic_integrate_requirements<
274 typename
std::enable_if<
276 has_is_zero<decltype(math::partial(std::declval<const typename T::term_type::cf_type &>(),
277 std::declval<const std::string &>()))>::value
280 is_addable_in_place<ResT>::value &&
282 std::is_constructible<ResT, int>::value>::type> {
283 static const bool value =
true;
287 template <
typename ResT,
typename T>
288 using i_cf_only_type = decltype(
289 math::integrate(std::declval<const typename T::term_type::cf_type &>(), std::declval<const std::string &>())
290 * std::declval<const T &>());
293 template <
typename ResT,
typename T,
typename =
void>
294 struct i_cf_only_enabler {
295 static const bool value =
false;
297 template <
typename ResT,
typename T>
298 struct i_cf_only_enabler<ResT, T,
299 typename
std::enable_if<std::is_same<ResT, i_cf_only_type<ResT, T>>::value>::type> {
300 static const bool value =
true;
302 template <
typename ResT,
typename It,
typename T = poisson_series>
303 void integrate_coefficient_only(ResT &retval, It it,
const std::string &name,
304 typename std::enable_if<i_cf_only_enabler<ResT, T>::value>::type * =
nullptr)
const 310 tmp.insert(
term_type(cf_type(1), it->m_key));
313 template <
typename ResT,
typename It,
typename T = poisson_series>
314 void integrate_coefficient_only(ResT &, It,
const std::string &,
315 typename std::enable_if<!i_cf_only_enabler<ResT, T>::value>::type * =
nullptr)
const 318 "unable to perform Poisson series integration: coefficient type is not integrable");
321 template <
typename T,
typename =
void>
322 struct integrate_type_ {
325 template <
typename T>
326 using npc_res_type = decltype((std::declval<const T &>() * std::declval<const typename T::term_type::cf_type &>())
327 / std::declval<
const key_integrate_type<T> &>());
328 template <
typename T>
329 struct integrate_type_<
330 T, typename
std::enable_if<!std::is_base_of<detail::polynomial_tag, typename T::term_type::cf_type>::value
331 && basic_integrate_requirements<T, npc_res_type<T>>::value>::type> {
332 using type = npc_res_type<T>;
336 template <
typename T>
337 using i_cf_type = decltype(std::declval<const typename T::term_type::cf_type &>()
338 / std::declval<
const key_integrate_type<T> &>());
340 template <
typename T>
342 = decltype(
math::partial(std::declval<
const i_cf_type<T> &>(), std::declval<const std::string &>()));
344 template <
typename T>
345 using pc_res_type = decltype(std::declval<
const i_cf_type_p<T> &>() * std::declval<const T &>());
346 template <
typename T>
347 struct integrate_type_<
348 T, typename
std::enable_if<
349 std::is_base_of<detail::polynomial_tag, typename T::term_type::cf_type>::value
350 && basic_integrate_requirements<T, pc_res_type<T>>::value &&
352 is_addable_in_place<pc_res_type<T>, npc_res_type<T>>::value &&
355 has_safe_cast<integer, decltype(math::degree(std::declval<const typename T::term_type::cf_type &>(),
356 std::declval<const symbol_fset &>()))>::value
359 std::is_constructible<i_cf_type_p<T>, i_cf_type<T>>::value &&
361 has_negate<i_cf_type_p<T>>::value>::type> {
362 using type = pc_res_type<T>;
365 template <
typename T>
366 using integrate_type =
typename std::enable_if<is_returnable<typename integrate_type_<T>::type>::value,
367 typename integrate_type_<T>::type>::type;
368 template <
typename T = poisson_series>
369 integrate_type<T> integrate_impl(
const std::string &s,
const typename base::term_type &term,
370 const std::true_type &)
const 377 }
catch (
const safe_cast_failure &) {
379 std::invalid_argument,
380 "unable to perform Poisson series integration: cannot convert polynomial degree to an integer");
385 std::invalid_argument,
386 "unable to perform Poisson series integration: polynomial coefficient has negative integral degree");
389 auto key_int = term.m_key.integrate(s, this->
m_symbol_set);
391 piranha_assert(key_int.first != 0);
395 tmp.insert(
term_type(cf_type(1), key_int.second));
396 i_cf_type_p<T> p_cf(term.m_cf / std::move(key_int.first));
397 integrate_type<T> retval(p_cf * tmp);
399 key_int = key_int.second.integrate(s, this->
m_symbol_set);
400 piranha_assert(key_int.first != 0);
407 tmp.insert(
term_type(cf_type(1), key_int.second));
408 retval += p_cf * tmp;
412 template <
typename T = poisson_series>
413 integrate_type<T> integrate_impl(
const std::string &,
const typename base::term_type &,
414 const std::false_type &)
const 417 "unable to perform Poisson series integration: coefficient type is not a polynomial");
421 template <
typename T>
422 using ti_type_divisor_
423 = decltype((std::declval<const T &>() * std::declval<const typename T::term_type::cf_type &>())
424 / std::declval<const integer &>());
425 template <
typename T>
426 using ti_type_divisor =
typename std::enable_if<
427 std::is_constructible<ti_type_divisor_<T>,
int>::value && is_addable_in_place<ti_type_divisor_<T>>::value
428 && std::is_base_of<detail::divisor_series_tag, typename T::term_type::cf_type>::value,
429 ti_type_divisor_<T>>::type;
430 template <
typename T = poisson_series>
431 ti_type_divisor<T> t_integrate_impl(
const std::vector<std::string> &names)
const 433 using return_type = ti_type<T>;
437 using k_value_type =
typename term_type::key_type::value_type;
440 using d_term_type =
typename d_series_type::term_type;
441 using d_cf_type =
typename d_term_type::cf_type;
442 using d_key_type =
typename d_term_type::key_type;
444 return_type retval(0);
446 piranha_assert(names.size() == this->
m_symbol_set.size());
447 const symbol_fset div_symbols(names.begin(), names.end());
448 piranha_assert(div_symbols.size() == names.size());
451 std::vector<integer> tmp_int;
458 const auto trig_vector = it->m_key.unpack(this->
m_symbol_set);
460 std::transform(trig_vector.begin(), trig_vector.end(), std::back_inserter(tmp_int),
461 [](
const k_value_type &n) {
return integer(n); });
468 bool first_nonzero_found =
false;
469 for (
const auto &n_int : tmp_int) {
473 piranha_assert(n_int > 0);
474 first_nonzero_found =
true;
478 piranha_throw(std::invalid_argument,
"an invalid trigonometric term was encountered while " 479 "attempting a time integration");
484 for (
auto &n_int : tmp_int) {
488 d_series_type div_series;
489 div_series.set_symbol_set(div_symbols);
492 div_key.insert(tmp_int.begin(), tmp_int.end(),
typename d_key_type::value_type(1));
494 div_series.insert(d_term_type(d_cf_type(1), std::move(div_key)));
498 auto tmp_key = it->m_key;
499 tmp_key.set_flavour(!tmp_key.get_flavour());
500 tmp_ps.insert(
term_type(it->m_cf, std::move(tmp_key)));
502 auto tmp = (std::move(tmp_ps) * std::move(div_series)) / cd;
504 if (!it->m_key.get_flavour()) {
507 retval += std::move(tmp);
512 template <
typename T>
514 = decltype(std::declval<const T &>().t_integrate_impl(std::declval<
const std::vector<std::string> &>()));
518 template <
typename Cf2>
589 template <
typename T = poisson_series>
605 template <
typename T = poisson_series>
641 template <
typename T = poisson_series>
642 integrate_type<T>
integrate(
const std::string &name)
const 647 integrate_type<T> retval(0);
651 auto key_int = it->m_key.integrate(name, this->
m_symbol_set);
654 if (key_int.first == 0) {
655 integrate_coefficient_only(retval, it, name);
663 tmp.insert(
term_type(cf_type(1), std::move(key_int.second)));
664 retval += (std::move(tmp) * it->m_cf) / key_int.first;
667 retval += integrate_impl(
668 name, *it, std::integral_constant<
bool, std::is_base_of<detail::polynomial_tag, Cf>::value>());
709 template <
typename T = poisson_series>
712 std::vector<std::string> names;
714 [](
const std::string &s) {
return "\\nu_{" + s +
"}"; });
715 return t_integrate_impl(names);
736 template <
typename T = poisson_series>
739 if (unlikely(!std::is_sorted(names.begin(), names.end()))) {
740 piranha_throw(std::invalid_argument,
"the list of symbol names must be ordered lexicographically");
743 names.erase(std::unique(names.begin(), names.end()), names.end());
744 if (unlikely(names.size() != this->
m_symbol_set.size())) {
745 piranha_throw(std::invalid_argument,
"the number of symbols passed in input must be equal to the " 746 "number of symbols of the Poisson series");
748 return t_integrate_impl(names);
755 template <
typename Series>
756 using ps_series_multiplier_enabler =
typename std::enable_if<std::is_base_of<poisson_series_tag, Series>::value>::type;
760 template <
typename Series>
764 template <
typename T>
765 using call_enabler =
typename std::enable_if<
767 void divide_by_two(Series &s)
const 771 piranha_assert(this->m_n_threads > 0u);
772 if (this->m_n_threads == 1u) {
778 using term_type =
typename Series::term_type;
779 auto &container = s._container();
780 std::atomic<bucket_size_type> total_erase_count(0u);
784 std::vector<term_type> term_list;
787 for (; start_idx != end_idx; ++start_idx) {
790 const auto &list = container._get_bucket_list(start_idx);
791 for (
const auto &t : list) {
793 if (unlikely(t.is_zero(this->m_ss))) {
794 term_list.push_back(t);
797 for (
const auto &t : term_list) {
798 container._erase(container._find(t, start_idx));
803 total_erase_count += erase_count;
806 const auto bpt =
static_cast<bucket_size_type>(container.bucket_count() / this->m_n_threads);
810 for (
unsigned i = 0u; i < this->m_n_threads; ++i) {
813 const auto end_idx = (i == this->m_n_threads - 1u) ? container.bucket_count()
828 const auto tot = total_erase_count.load();
829 piranha_assert(tot <= s.size());
830 container._update_size(static_cast<bucket_size_type>(s.size() - tot));
849 template <
typename T = Series, call_enabler<T> = 0>
852 auto retval(this->plain_multiplication());
853 divide_by_two(retval);
typename Series::size_type bucket_size_type
The size type of Series.
void wait_all()
Wait on all the futures.
Type trait for multipliable key.
detail::math_integrate_type< T > integrate(const T &x, const std::string &str)
Integration.
mp_integer< 1 > integer
Alias for piranha::mp_integer with 1 limb of static storage.
detail::math_partial_type< T > partial(const T &x, const std::string &str)
Partial derivative.
substitutable_series()=default
Defaulted default constructor.
poisson_series()=default
Defaulted default constructor.
detail::math_cos_type< T > cos(const T &x)
Cosine.
const_iterator end() const
Const end iterator.
void negate(T &x)
In-place negation.
ti_type< T > t_integrate(std::vector< std::string > names) const
Time integration (alternative overload).
#define PIRANHA_FORWARDING_CTOR(Derived, Base)
Constructor-forwarding macro.
void get_all()
Get all the futures.
static enqueue_t< F &&, Args &&... > enqueue(unsigned n, F &&f, Args &&... args)
Enqueue task.
auto degree(const T &x) -> decltype(degree_impl< T >()(x))
Total degree.
#define piranha_throw(exception_type,...)
Exception-throwing macro.
boost::container::flat_set< std::string > symbol_fset
Flat set of symbols.
Key key_type
Alias for the key type.
sin_type< T > sin() const
Sine.
poisson_series & operator=(const poisson_series &other)=default
Copy assignment operator.
integrate_type< T > integrate(const std::string &name) const
Integration.
cos_type< T > cos() const
Cosine.
const_iterator begin() const
Const begin iterator.
Cf cf_type
Alias for the coefficient type.
bool is_zero(const T &x)
Zero test.
Class to store a list of futures.
term< Cf, rtk_monomial > term_type
Alias for term type.
t_substitutable_series()=default
Defaulted default constructor.
~poisson_series()
Trivial destructor.
ipow_substitutable_series()=default
Defaulted default constructor.
ti_type< T > t_integrate() const
Time integration.
symbol_fset m_symbol_set
Symbol set.
container_type m_container
Terms container.
power_series()=default
Defaulted default constructor.
#define PIRANHA_TT_CHECK(tt,...)
Macro for static type trait checks.
Series operator()() const
Call operator.
Type trait to detect series types.
auto gcd3(T &out, const T &a, const T &b) -> decltype(gcd3_impl< T >()(out, a, b))
Ternary GCD.
#define PIRANHA_FORWARDING_ASSIGNMENT(Derived, Base)
Assignment-forwarding macro.
detail::math_sin_type< T > sin(const T &x)
Sine.
safe_cast_type< To, From > safe_cast(const From &x)
Safe cast.
degree_type< T > degree() const
Total degree.
void push_back(std::future< T > &&f)
Move-insert a future.