piranha  0.10
ipow_substitutable_series.hpp
1 /* Copyright 2009-2017 Francesco Biscani (bluescarni@gmail.com)
2 
3 This file is part of the Piranha library.
4 
5 The Piranha library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8  * the GNU Lesser General Public License as published by the Free
9  Software Foundation; either version 3 of the License, or (at your
10  option) any later version.
11 
12 or
13 
14  * the GNU General Public License as published by the Free Software
15  Foundation; either version 3 of the License, or (at your option) any
16  later version.
17 
18 or both in parallel, as here.
19 
20 The Piranha library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the Piranha library. If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #ifndef PIRANHA_IPOW_SUBSTITUTABLE_SERIES_HPP
30 #define PIRANHA_IPOW_SUBSTITUTABLE_SERIES_HPP
31 
32 #include <string>
33 #include <type_traits>
34 #include <utility>
35 
36 #include <piranha/forwarding.hpp>
37 #include <piranha/mp_integer.hpp>
38 #include <piranha/series.hpp>
39 #include <piranha/symbol_utils.hpp>
40 #include <piranha/type_traits.hpp>
41 
42 namespace piranha
43 {
44 
45 inline namespace impl
46 {
47 
48 struct ipow_substitutable_series_tag {
49 };
50 }
51 
53 
74 template <typename Series, typename Derived>
75 class ipow_substitutable_series : public Series, ipow_substitutable_series_tag
76 {
77  typedef Series base;
78  // Detect subs term.
79  template <typename Term, typename T>
80  struct subs_term_score {
81  static const unsigned value
83  + (static_cast<unsigned>(key_has_ipow_subs<typename Term::key_type, T>::value) << 1u);
84  };
85  // Case 1: subs only on cf.
86  template <typename T, typename Term>
87  using cf_subs_type
88  = decltype(math::ipow_subs(std::declval<typename Term::cf_type const &>(), std::declval<std::string const &>(),
89  std::declval<const integer &>(), std::declval<T const &>()));
90  template <typename T, typename Term>
91  using ret_type_1 = decltype(std::declval<const cf_subs_type<T, Term> &>() * std::declval<Derived const &>());
92  template <typename T, typename Term, typename std::enable_if<subs_term_score<Term, T>::value == 1u, int>::type = 0>
93  static ret_type_1<T, Term> subs_term_impl(const Term &t, const symbol_idx &idx, const std::string &name,
94  const integer &n, const T &x, const symbol_fset &s_set)
95  {
96  piranha_assert(ss_index_of(s_set, name) == idx);
97  (void)idx;
98  Derived tmp;
99  tmp.set_symbol_set(s_set);
100  tmp.insert(Term(typename Term::cf_type(1), t.m_key));
101  // NOTE: use moves here in case the multiplication can take advantage.
102  return math::ipow_subs(t.m_cf, name, n, x) * std::move(tmp);
103  }
104  // Case 2: subs only on key.
105  template <typename T, typename Term>
106  using k_subs_type = typename decltype(std::declval<const typename Term::key_type &>().ipow_subs(
107  std::declval<const symbol_idx &>(), std::declval<const integer &>(), std::declval<const T &>(),
108  std::declval<const symbol_fset &>()))::value_type::first_type;
109  template <typename T, typename Term>
110  using ret_type_2_ = decltype(std::declval<Derived const &>() * std::declval<const k_subs_type<T, Term> &>());
111  template <typename T, typename Term>
112  using ret_type_2 = typename std::enable_if<is_addable_in_place<ret_type_2_<T, Term>>::value
113  && std::is_constructible<ret_type_2_<T, Term>, const int &>::value,
114  ret_type_2_<T, Term>>::type;
115  template <typename T, typename Term, typename std::enable_if<subs_term_score<Term, T>::value == 2u, int>::type = 0>
116  static ret_type_2<T, Term> subs_term_impl(const Term &t, const symbol_idx &idx, const std::string &name,
117  const integer &n, const T &x, const symbol_fset &s_set)
118  {
119  piranha_assert(ss_index_of(s_set, name) == idx);
120  (void)name;
121  ret_type_2<T, Term> retval(0);
122  auto ksubs = t.m_key.ipow_subs(idx, n, x, s_set);
123  for (auto &p : ksubs) {
124  Derived tmp;
125  tmp.set_symbol_set(s_set);
126  tmp.insert(Term{t.m_cf, std::move(p.second)});
127  // NOTE: possible use of multadd here in the future.
128  retval += std::move(tmp) * std::move(p.first);
129  }
130  return retval;
131  }
132  // Case 3: subs on cf and key.
133  // NOTE: the checks on type 2 are already present in the alias above.
134  template <typename T, typename Term>
135  using ret_type_3
136  = decltype(std::declval<const cf_subs_type<T, Term> &>() * std::declval<const ret_type_2<T, Term> &>());
137  template <typename T, typename Term, typename std::enable_if<subs_term_score<Term, T>::value == 3u, int>::type = 0>
138  static ret_type_3<T, Term> subs_term_impl(const Term &t, const symbol_idx &idx, const std::string &name,
139  const integer &n, const T &x, const symbol_fset &s_set)
140  {
141  piranha_assert(ss_index_of(s_set, name) == idx);
142  // Accumulator for the sum below. This is the same type resulting from case 2.
143  ret_type_2<T, Term> acc(0);
144  auto ksubs = t.m_key.ipow_subs(idx, n, x, s_set);
145  auto cf_subs = math::ipow_subs(t.m_cf, name, n, x);
146  for (auto &p : ksubs) {
147  Derived tmp;
148  tmp.set_symbol_set(s_set);
149  tmp.insert(Term(typename Term::cf_type(1), std::move(p.second)));
150  // NOTE: multadd chance.
151  acc += std::move(tmp) * std::move(p.first);
152  }
153  return std::move(cf_subs) * std::move(acc);
154  }
155  // Initial definition of the subs type.
156  template <typename T>
157  using subs_type_ = decltype(subs_term_impl(std::declval<typename Series::term_type const &>(),
158  std::declval<const symbol_idx &>(), std::declval<const std::string &>(),
159  std::declval<const integer &>(), std::declval<const T &>(),
160  std::declval<symbol_fset const &>()));
161  // Enable conditionally based on the common requirements in the ipow_subs() method.
162  template <typename T>
163  using ipow_subs_type = enable_if_t<
164  conjunction<std::is_constructible<subs_type_<T>, const int &>, is_addable_in_place<subs_type_<T>>>::value,
165  subs_type_<T>>;
166  // Enabler for the alternate overload.
167  template <typename Int>
168  using ipow_subs_int_enabler = enable_if_t<std::is_integral<Int>::value, int>;
169 
170 public:
172  ipow_substitutable_series() = default;
179 
188 
196  {
198  PIRANHA_TT_CHECK(is_series, Derived);
199  PIRANHA_TT_CHECK(std::is_base_of, ipow_substitutable_series, Derived);
200  }
203 
223  template <typename T>
224  ipow_subs_type<T> ipow_subs(const std::string &name, const integer &n, const T &x) const
225  {
226  const auto idx = ss_index_of(this->m_symbol_set, name);
227  ipow_subs_type<T> retval(0);
228  for (const auto &t : this->m_container) {
229  retval += subs_term_impl(t, idx, name, n, x, this->m_symbol_set);
230  }
231  return retval;
232  }
234 
251  template <typename T, typename Int, ipow_subs_int_enabler<Int> = 0>
252  ipow_subs_type<T> ipow_subs(const std::string &name, const Int &n, const T &x) const
253  {
254  return this->ipow_subs(name, integer(n), x);
255  }
256 };
257 
258 inline namespace impl
259 {
260 
261 // Enabler for the specialisation of ipow_subs functor for ipow_subs series.
262 template <typename Series, typename T>
263 using ipow_subs_mem_t = decltype(std::declval<const Series &>().ipow_subs(
264  std::declval<const std::string &>(), std::declval<const integer &>(), std::declval<const T &>()));
265 
266 template <typename Series, typename T>
267 using ipow_subs_impl_ipow_subs_series_enabler
268  = enable_if_t<conjunction<std::is_base_of<ipow_substitutable_series_tag, Series>,
269  is_detected<ipow_subs_mem_t, Series, T>>::value>;
270 }
271 
272 namespace math
273 {
274 
276 
280 template <typename Series, typename T>
281 struct ipow_subs_impl<Series, T, ipow_subs_impl_ipow_subs_series_enabler<Series, T>> {
283 
295  auto operator()(const Series &s, const std::string &name, const integer &n, const T &x) const
296  -> decltype(s.ipow_subs(name, n, x))
297  {
298  return s.ipow_subs(name, n, x);
299  }
300 };
301 }
302 }
303 
304 #endif
Multiprecision integer class.
Definition: mp++.hpp:869
mp_integer< 1 > integer
Alias for piranha::mp_integer with 1 limb of static storage.
Definition: mp_integer.hpp:63
In-place addable type trait.
#define PIRANHA_FORWARDING_CTOR(Derived, Base)
Constructor-forwarding macro.
Definition: forwarding.hpp:50
Forwarding macros.
Default functor for the implementation of piranha::math::ipow_subs().
Definition: mp_integer.hpp:270
boost::container::flat_set< std::string > symbol_fset
Flat set of symbols.
auto operator()(const Series &s, const std::string &name, const integer &n, const T &x) const -> decltype(s.ipow_subs(name, n, x))
Call operator.
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.
ipow_subs_type< T > ipow_subs(const std::string &name, const Int &n, const T &x) const
Substitution.
ipow_subs_type< T > ipow_subs(const std::string &name, const integer &n, const T &x) const
Substitution.
Type trait to detect the presence of the integral power substitution method in keys.
Definition: mp_integer.hpp:557
Root piranha namespace.
Definition: array_key.hpp:52
Type traits.
ipow_substitutable_series()=default
Defaulted default constructor.
Toolbox for series suitable for integral power substitution.
ipow_substitutable_series & operator=(const ipow_substitutable_series &other)=default
Copy assignment operator.
#define PIRANHA_TT_CHECK(tt,...)
Macro for static type trait checks.
Type trait to detect series types.
Definition: series_fwd.hpp:49
Type trait to detect the availability of the piranha::math::ipow_subs() function. ...
Definition: mp_integer.hpp:530
#define PIRANHA_FORWARDING_ASSIGNMENT(Derived, Base)
Assignment-forwarding macro.
Definition: forwarding.hpp:68
math_ipow_subs_t< T, U > ipow_subs(const T &x, const std::string &name, const integer &n, const U &y)
Substitution of integral power.
Definition: mp_integer.hpp:312