7 #ifndef ALPSCORE_PIEACEWISE_POLYNOMIAL_HPP 8 #define ALPSCORE_PIEACEWISE_POLYNOMIAL_HPP 12 #include <type_traits> 15 #include <boost/multi_array.hpp> 16 #include <boost/typeof/typeof.hpp> 43 typename std::enable_if<boost::is_floating_point<T>::value, T>::type
44 outer_product(T a, T b) {
50 outer_product(
const std::complex<T> &a,
const std::complex<T> &b) {
51 return std::conj(a) * b;
55 typename std::enable_if<boost::is_floating_point<T>::value, T>::type
62 conjg(
const std::complex<T> &a) {
66 template<
typename T,
typename Op>
67 struct pp_element_wise_op {
68 void perform(
const T *p1,
const T *p2, T *p_r,
int k1,
int k2,
int k_r)
const {
70 int k = std::min(k1, k2);
72 for (
int i=0; i<k_r+1; ++i) {
75 for (
int i=0; i<k+1; ++i) {
76 p_r[i] = op(p1[i], p2[i]);
82 struct pp_plus :
public pp_element_wise_op<T, std::plus<T> > {};
85 struct pp_minus :
public pp_element_wise_op<T, std::minus<T> > {};
88 template<
typename T,
typename Op>
91 if (f1.section_edges_ != f2.section_edges_) {
92 throw std::runtime_error(
"Cannot add two numerical functions with different sections!");
95 const int k_new = std::max(f1.
order(), f2.
order());
98 const int k_min = std::min(f1.
order(), f2.
order());
101 op.perform(&f1.coeff_[s][0], &f2.coeff_[s][0], &
result.coefficient(s,0), f1.
order(), f2.
order(), k_min);
117 typedef boost::multi_array<T, 2> coefficient_type;
119 template<
typename TT,
typename Op>
123 template<
typename TT>
127 template<
typename TT>
131 template<
typename TT>
134 template<
typename TT>
142 std::vector<double> section_edges_;
148 coefficient_type coeff_;
152 void check_range(
double x)
const {
153 if (x < section_edges_[0] || x > section_edges_[section_edges_.size() - 1]) {
154 throw std::runtime_error(
"Give x is out of the range.");
158 void check_validity()
const {
160 throw std::runtime_error(
"pieacewise_polynomial object is not properly constructed!");
164 void set_validity() {
166 valid_ = valid_ && (n_sections_ >= 1);
168 valid_ = valid_ && (section_edges_.size() == std::size_t(n_sections_) + 1);
170 valid_ = valid_ && (coeff_.shape()[0] == std::size_t(n_sections_));
172 valid_ = valid_ && (coeff_.shape()[1] == std::size_t(k_+1));
174 for (
int i = 0; i < n_sections_; ++i) {
175 valid_ = valid_ && (section_edges_[i] < section_edges_[i + 1]);
185 n_sections_(section_edges.size()-1),
186 section_edges_(section_edges),
187 coeff_(boost::extents[n_sections_][k+1]),
189 std::fill(coeff_.origin(), coeff_.origin()+coeff_.num_elements(), 0.0);
196 const std::vector<double> §ion_edges,
197 const boost::multi_array<T, 2> &coeff) : k_(coeff.shape()[1]-1),
198 n_sections_(section_edges.
size() - 1),
199 section_edges_(section_edges),
200 coeff_(coeff), valid_(false) {
208 n_sections_ = other.n_sections_;
209 section_edges_ = other.section_edges_;
211 coeff_.resize(boost::extents[other.coeff_.shape()[0]][other.coeff_.shape()[1]]);
212 coeff_ = other.coeff_;
213 valid_ = other.valid_;
223 int num_sections()
const {
231 inline double section_edge(
int i)
const {
232 assert(i >= 0 && i < section_edges_.size());
236 return section_edges_[i];
240 const std::vector<double> §ion_edges()
const {
244 return section_edges_;
248 inline const T& coefficient(
int i,
int p)
const {
249 assert(i >= 0 && i < section_edges_.size());
250 assert(p >= 0 && p <= k_);
258 inline T& coefficient(
int i,
int p) {
259 assert(i >= 0 && std::size_t(i) < section_edges_.size());
260 assert(p >= 0 && p <= k_);
269 std::fill(coeff_.origin(), coeff_.origin()+coeff_.num_elements(), 0.0);
273 inline T compute_value(
double x)
const {
277 return compute_value(x, find_section(x));
281 inline T compute_value(
double x,
int section)
const {
285 if (x < section_edges_[section] || (x != section_edges_.back() && x >= section_edges_[section + 1])) {
286 throw std::runtime_error(
"The given x is not in the given section.");
289 const double dx = x - section_edges_[section];
290 T
r = 0.0, x_pow = 1.0;
291 for (
int p = 0; p < k_ + 1; ++p) {
292 r += coeff_[section][p] * x_pow;
299 int find_section(
double x)
const {
303 if (x == section_edges_[0]) {
305 }
else if (x == section_edges_.back()) {
306 return coeff_.size() - 1;
309 std::vector<double>::const_iterator it =
310 std::upper_bound(section_edges_.begin(), section_edges_.end(), x);
312 return (&(*it) - &(section_edges_[0]));
319 if (section_edges_ != other.section_edges_) {
320 throw std::runtime_error(
"Computing overlap between piecewise polynomials with different section edges are not supported");
322 typedef BOOST_TYPEOF(static_cast<T>(1.0)*static_cast<T2>(1.0)) Tr;
324 const int k = this->order();
325 const int k2 = other.
order();
328 std::vector<double> x_min_power(k+k2+2), dx_power(k+k2+2);
330 for (
int s = 0; s < n_sections_; ++s) {
332 const double dx = section_edges_[s + 1] - section_edges_[s];
333 for (std::size_t p = 1; p < dx_power.size(); ++p) {
334 dx_power[p] = dx * dx_power[p - 1];
337 for (
int p = 0; p < k + 1; ++p) {
338 for (
int p2 = 0; p2 < k2 + 1; ++p2) {
339 r += detail::outer_product((Tr) coeff_[s][p], (Tr) other.coeff_[s][p2])
340 * dx_power[p + p2 + 1] / (p + p2 + 1.0);
348 double squared_norm()
const {
349 return static_cast<double>(this->overlap(*
this));
354 return (n_sections_ == other.n_sections_) &&
355 (section_edges_ == other.section_edges_) &&
356 (coeff_ == other.coeff_);
363 ar[path+
"/num_sections"] << num_sections();
364 ar[path+
"/section_edges"] << section_edges_;
365 ar[path+
"/coefficients"] << coeff_;
371 ar[path+
"/num_sections"] >> n_sections_;
372 ar[path+
"/section_edges"] >> section_edges_;
373 ar[path+
"/coefficients"] >> coeff_;
399 section_edges_.resize(n_sections_+1);
400 broadcast(comm, §ion_edges_[0], n_sections_+1, root);
402 coeff_.resize(boost::extents[n_sections_][k_+1]);
403 broadcast(comm, coeff_.origin(), (k_+1)*n_sections_, root);
416 return detail::do_op(f1, f2, detail::pp_plus<T>());
423 return detail::do_op(f1, f2, detail::pp_minus<T>());
431 pp_copy.coeff_.origin(), pp_copy.coeff_.origin() + pp_copy.coeff_.num_elements(),
432 pp_copy.coeff_.origin(), std::bind1st(std::multiplies<T>(), scalar)
443 for (std::size_t l = 0; l < pps.size(); ++l) {
444 pp_type pp_new(pps[l]);
445 for (std::size_t l2 = 0; l2 < l; ++l2) {
446 const T overlap = pps[l2].overlap(pps[l]);
447 pp_new = pp_new - overlap * pps[l2];
449 double norm = pp_new.overlap(pp_new);
450 pps[l] = (1.0 /
std::sqrt(norm)) * pp_new;
456 #endif //ALPSCORE_PIEACEWISE_POLYNOMIAL_HPP piecewise_polynomial< T > operator+(const piecewise_polynomial< T > &f1, const piecewise_polynomial< T > &f2)
Add piecewise_polynomial objects.
void load(archive &ar, std::string const &path, T &value, std::vector< std::size_t > chunk=std::vector< std::size_t >(), std::vector< std::size_t >=std::vector< std::size_t >())
boost::array< T, N > sqrt(boost::array< T, N > arg)
std::enable_if<!is_sequence< T >::value, std::size_t >::type size(T const &)
void broadcast(C const &c, P &p, int r=0)
piecewise_polynomial< T > operator-(const piecewise_polynomial< T > &f1, const piecewise_polynomial< T > &f2)
Substract piecewise_polynomial objects.
const piecewise_polynomial< T > operator*(T scalar, const piecewise_polynomial< T > &pp)
Multiply piecewise_polynomial by a scalar.
bool operator==(const dictionary &lhs, const dictionary &rhs)
mean_result< T > transform(no_prop, const transformer< T > &tf, const InResult &in)
Encapsulation of an MPI communicator and some communicator-related operations.
T norm(T x, T y=T(), T z=T())
void orthonormalize(std::vector< piecewise_polynomial< T > > &pps)
Gram-Schmidt orthonormalization.
int order() const
Order of the polynomial.
int num_sections() const
Number of sections.
std::string get_context() const
Functions to MPI-broadcast internal data structures.
traits< Acc >::result_type result(const Acc &acc)
void broadcast(const communicator &comm, T *vals, std::size_t count, int root)
Broadcasts array vals of a primitive type T, length count on communicator comm with root root ...
T r(T x, T y=T(), T z=T())
const std::vector< double > & section_edges() const
Return a refence to end points.
Class representing a piecewise polynomial and utilities.
void save(archive &ar, std::string const &path, T const &value, std::vector< std::size_t >=std::vector< std::size_t >(), std::vector< std::size_t > chunk=std::vector< std::size_t >(), std::vector< std::size_t >=std::vector< std::size_t >())