29 #ifndef PIRANHA_DIVISOR_SERIES_HPP 30 #define PIRANHA_DIVISOR_SERIES_HPP 33 #include <boost/container/container_fwd.hpp> 34 #include <boost/iterator/transform_iterator.hpp> 35 #include <initializer_list> 40 #include <type_traits> 44 #include <piranha/base_series_multiplier.hpp> 45 #include <piranha/config.hpp> 46 #include <piranha/detail/divisor_series_fwd.hpp> 47 #include <piranha/detail/polynomial_fwd.hpp> 48 #include <piranha/divisor.hpp> 51 #include <piranha/invert.hpp> 52 #include <piranha/ipow_substitutable_series.hpp> 53 #include <piranha/is_cf.hpp> 54 #include <piranha/key_is_multipliable.hpp> 55 #include <piranha/math.hpp> 56 #include <piranha/mp_integer.hpp> 57 #include <piranha/power_series.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> 71 struct divisor_series_tag {
76 struct is_divisor_series_key {
77 static const bool value =
false;
81 struct is_divisor_series_key<divisor<T>> {
82 static const bool value =
true;
88 using type =
typename T::base;
110 template <
typename Cf,
typename Key>
112 :
public power_series<ipow_substitutable_series<
113 substitutable_series<series<Cf, Key, divisor_series<Cf, Key>>, divisor_series<Cf, Key>>,
114 divisor_series<Cf, Key>>,
115 divisor_series<Cf, Key>>,
116 detail::divisor_series_tag
123 friend struct detail::base_getter;
127 substitutable_series<series<Cf, Key, divisor_series<Cf, Key>>, divisor_series<Cf, Key>>,
128 divisor_series<Cf, Key>>,
129 divisor_series<Cf, Key>>;
131 using dv_type =
typename Key::value_type;
134 template <typename T, enable_if_t<std::is_integral<T>::value,
int> = 0>
135 static void expo_increase(T &e)
137 if (unlikely(e == std::numeric_limits<T>::max())) {
138 piranha_throw(std::overflow_error,
"overflow in the computation of the partial derivative " 139 "of a divisor series");
141 e =
static_cast<T
>(e + T(1));
143 template <typename T, enable_if_t<!std::is_integral<T>::value,
int> = 0>
144 static void expo_increase(T &e)
149 template <typename T, enable_if_t<std::is_integral<T>::value,
int> = 0>
150 static auto safe_mult(
const T &n,
const T &m) -> decltype(n * m)
154 return static_cast<decltype(n * m)
>(ret);
156 template <typename T, enable_if_t<!std::is_integral<T>::value,
int> = 0>
157 static auto safe_mult(
const T &n,
const T &m) -> decltype(-(n * m))
162 template <
typename T>
163 using d_partial_type_0
164 = decltype(std::declval<const dv_type &>() * std::declval<const dv_type &>() * std::declval<const T &>());
165 template <
typename T>
166 using d_partial_type_1 = decltype(std::declval<const T &>() * std::declval<
const d_partial_type_0<T> &>());
168 template <
typename T>
169 using d_partial_type = enable_if_t<
170 conjunction<std::is_constructible<d_partial_type_1<T>, d_partial_type_0<T>>,
171 std::is_constructible<d_partial_type_1<T>,
int>, is_addable_in_place<d_partial_type_1<T>>>::value,
172 d_partial_type_1<T>>;
173 template <
typename T = divisor_series>
174 d_partial_type<T> d_partial_impl(
typename T::term_type::key_type &key,
const symbol_idx &p)
const 179 piranha_assert(key.size() != 0u);
184 const auto it_f = key.m_container.end();
185 auto it = key.m_container.begin(), it_b(it);
186 auto first(*it), first_copy(*it);
188 using vs_type = decltype(first.v.size());
190 for (; it != it_f; ++it) {
191 tmp_div.m_container.insert(*it);
194 key.m_container.erase(it_b);
196 const auto mult = safe_mult(first.e, first.v[static_cast<vs_type>(p)]);
198 expo_increase(first.e);
200 tmp_div.m_container.insert(first);
204 tmp_ds.insert(
term_type(cf_type(1), std::move(tmp_div)));
206 d_partial_type<T> retval(mult * tmp_ds);
208 if (!key.m_container.empty()) {
211 tmp_div_01.m_container.insert(std::move(first_copy));
214 tmp_ds_01.insert(
term_type(cf_type(1), std::move(tmp_div_01)));
216 retval += tmp_ds_01 * d_partial_impl(key, p);
220 template <
typename T = divisor_series>
221 d_partial_type<T> divisor_partial(
const typename T::term_type &term,
const symbol_idx &p)
const 226 return d_partial_type<T>(0);
231 if (sd.first.size() == 0u) {
232 return d_partial_type<T>(0);
238 tmp_ds.insert(
term_type(term.m_cf, std::move(sd.second)));
240 return tmp_ds * d_partial_impl(sd.first, p);
243 template <
typename T>
244 using partial_type_ = decltype(
245 math::partial(std::declval<const typename T::term_type::cf_type &>(), std::declval<const std::string &>())
246 * std::declval<const T &>()
247 + std::declval<
const d_partial_type<T> &>());
248 template <
typename T>
249 using partial_type = enable_if_t<
250 conjunction<std::is_constructible<partial_type_<T>,
int>, is_addable_in_place<partial_type_<T>>>::value,
253 template <
typename T>
254 using integrate_type_ = decltype(
255 math::integrate(std::declval<const typename T::term_type::cf_type &>(), std::declval<const std::string &>())
256 * std::declval<const T &>());
257 template <
typename T>
258 using integrate_type = enable_if_t<
259 conjunction<std::is_constructible<integrate_type_<T>,
int>, is_addable_in_place<integrate_type_<T>>>::value,
263 template <
typename T>
264 using inverse_type = decltype(
math::invert(std::declval<
const typename detail::base_getter<T>::type &>()));
267 template <
typename T,
typename =
void>
268 struct has_special_invert {
269 static constexpr
bool value =
false;
271 template <
typename T>
272 struct has_special_invert<
273 T, enable_if_t<conjunction<
274 detail::poly_in_cf<T>,
275 std::is_constructible<inverse_type<T>, decltype(std::declval<const inverse_type<T> &>()
276 / std::declval<const integer &>())>>::value>> {
277 static constexpr
bool value =
true;
280 template <typename T = divisor_series, enable_if_t<!has_special_invert<T>::value,
int> = 0>
281 inverse_type<T> invert_impl()
const 287 template <typename T = divisor_series, enable_if_t<has_special_invert<T>::value,
int> = 0>
288 inverse_type<T> invert_impl()
const 290 return special_invert<inverse_type<T>>(*this);
293 template <
typename RetT,
typename T,
294 enable_if_t<std::is_base_of<detail::polynomial_tag, typename T::term_type::cf_type>::value,
int> = 0>
295 RetT special_invert(
const T &s)
const 297 if (s.is_single_coefficient() && !s.empty()) {
299 using term_type =
typename RetT::term_type;
303 auto lc = s._container().begin()->m_cf.integral_combination();
305 piranha_assert(!lc.empty());
308 const std::string &operator()(
const typename decltype(lc)::value_type &p)
const 313 symbol_fset ss(boost::container::ordered_unique_range_t{},
314 boost::make_transform_iterator(lc.begin(), t_iter{}),
315 boost::make_transform_iterator(lc.end(), t_iter{}));
317 piranha_assert(ss.size() == lc.size());
318 std::vector<integer> v_int;
319 std::transform(lc.begin(), lc.end(), std::back_inserter(v_int),
320 [](
const typename decltype(lc)::value_type &p) {
return p.second; });
323 bool first_nonzero_found =
false, need_negate =
false;
325 for (
auto &n : v_int) {
330 first_nonzero_found =
true;
341 piranha_assert(cd.sgn() > 0);
343 for (
auto &n : v_int) {
348 tmp_key.insert(v_int.begin(), v_int.end(),
integer{1});
351 retval.set_symbol_set(ss);
352 retval.insert(
term_type(cf_type(1), std::move(tmp_key)));
358 return RetT(retval / cd);
359 }
catch (
const std::invalid_argument &) {
368 template <
typename RetT,
typename T,
369 enable_if_t<!std::is_base_of<detail::polynomial_tag, typename T::term_type::cf_type>::value,
int> = 0>
370 RetT special_invert(
const T &s)
const 372 if (s.is_single_coefficient() && !s.empty()) {
373 return special_invert<RetT>(s._container().begin()->m_cf);
380 template <
typename Cf2>
460 template <
typename T = divisor_series>
463 return invert_impl();
491 template <
typename T = divisor_series>
492 partial_type<T>
partial(
const std::string &name)
const 496 partial_type<T> retval(0);
502 tmp.insert(
term_type(cf_type(1), it->m_key));
503 retval +=
math::partial(it->m_cf, name) * tmp + divisor_partial(*it, idx);
527 template <
typename T = divisor_series>
528 integrate_type<T>
integrate(
const std::string &name)
const 532 integrate_type<T> retval(0);
541 const auto it2_f = it->m_key.m_container.end();
542 for (
auto it2 = it->m_key.m_container.begin(); it2 != it2_f; ++it2) {
543 using size_type = decltype(it2->v.size());
544 piranha_assert(idx < it2->v.size());
545 if (unlikely(it2->v[static_cast<size_type>(idx)] != 0)) {
546 piranha_throw(std::invalid_argument,
"unable to integrate with respect to divisor variables");
552 tmp.insert(
term_type(cf_type(1), it->m_key));
562 template <
typename Series>
563 using divisor_series_multiplier_enabler = enable_if_t<std::is_base_of<divisor_series_tag, Series>::value>;
567 template <
typename Series>
572 template <
typename T>
574 = enable_if_t<key_is_multipliable<typename T::term_type::cf_type, typename T::term_type::key_type>::value,
int>;
591 template <
typename T = Series, call_enabler<T> = 0>
594 return this->plain_multiplication();
auto invert(const T &x) -> decltype(invert_impl< T >()(x))
Compute the inverse.
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.
~divisor_series()
Trivial destructor.
Type trait to detect coefficient types.
const_iterator end() const
Const end iterator.
void negate(T &x)
In-place negation.
#define PIRANHA_FORWARDING_CTOR(Derived, Base)
Constructor-forwarding macro.
integrate_type< T > integrate(const std::string &name) const
Integration.
#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.
typename container_type::size_type size_type
Size type.
Series operator()() const
Call operator.
const_iterator begin() const
Const begin iterator.
Cf cf_type
Alias for the coefficient type.
symbol_fset::size_type symbol_idx
Symbol index.
symbol_idx ss_index_of(const symbol_fset &ref, const std::string &name)
Identify the index of a symbol in a symbol_fset.
bool is_zero(const T &x)
Zero test.
term< Cf, Key > term_type
Alias for term type.
partial_type< T > partial(const std::string &name) const
Partial derivative.
ipow_substitutable_series()=default
Defaulted default constructor.
divisor_series & operator=(const divisor_series &other)=default
Copy assignment operator.
symbol_fset m_symbol_set
Symbol set.
divisor_series()=default
Defaulted default constructor.
container_type m_container
Terms container.
power_series()=default
Defaulted default constructor.
#define PIRANHA_TT_CHECK(tt,...)
Macro for static type trait checks.
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.
inverse_type< T > invert() const
Inversion.