WaveBlocksND
hawp_evaluator.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <functional>
4 
5 #include <Eigen/Core>
6 
7 #include "../math/pi.hpp"
8 #include "../math/kahan_sum.hpp"
9 
10 #include "hawp_paramset.hpp"
11 #include "shapes/shape_enum.hpp"
13 
14 
15 namespace waveblocks {
16  namespace wavepackets {
17  using shapes::ShapeEnum;
18  using shapes::ShapeSlice;
19 
40  template<dim_t D, class MultiIndex, int N>
42  {
43  public:
44  typedef Eigen::Matrix<complex_t,D,D> CMatrixDD;
45  typedef Eigen::Array<complex_t,1,N> CArray1N;
46  typedef Eigen::Matrix<complex_t,D,N> CMatrixDN;
47  typedef Eigen::Matrix<real_t,D,N> RMatrixDN;
48 
49  private:
52  const ShapeEnum<D,MultiIndex>* enumeration_;
53 
57  int npts_;
58 
62  CMatrixDN dx_;
63 
67  CMatrixDD Qinv_;
68 
72  CMatrixDD Qh_Qinvt_;
73 
77  CMatrixDN Qinv_dx_;
78 
82  std::vector<real_t> sqrt_;
83 
84  public:
94  const HaWpParamSet<D>* parameters,
95  const ShapeEnum<D,MultiIndex>* enumeration,
96  const CMatrixDN &x)
97  : eps_(eps)
98  , parameters_(parameters)
99  , enumeration_(enumeration)
100  , npts_(x.cols())
101  , sqrt_()
102  {
103  RMatrix<D,1> const& q = parameters_->q();
104  CMatrix<D,D> const& Q = parameters_->Q();
105 
106  // precompute ...
107  dx_ = x.colwise() - q.template cast<complex_t>();
108  Qinv_ = Q.inverse();
109  Qh_Qinvt_ = Q.adjoint()*Qinv_.transpose();
110  Qinv_dx_ = Qinv_*dx_;
111 
112  //precompute sqrt lookup table
113  {
114  int limit = 0;
115  for (dim_t d = 0; d < D; d++)
116  limit = std::max(limit, enumeration_->limit(d) );
117 
118  sqrt_.resize(limit+2);
119 
120  for (int i = 0; i <= limit+1; i++)
121  sqrt_[i] = std::sqrt( real_t(i) );
122  }
123  }
124 
130  CArray1N seed() const
131  {
132  RMatrix<D,1> const& p = parameters_->p();
133  CMatrix<D,D> const& P = parameters_->P();
134 
135  CMatrixDN P_Qinv_dx = P*Qinv_dx_;
136 
137  CArray1N pr1 = ( dx_.array() * P_Qinv_dx.array() ).colwise().sum();
138  CArray1N pr2 = ( p.transpose()*dx_ ).array();
139 
140  CArray1N e = complex_t(0.0, 1.0)/(eps_*eps_) * (0.5*pr1 + pr2);
141 
142  return e.exp() / std::pow(math::pi<real_t>()*eps_*eps_, D/4.0);
143  }
144 
167  HaWpBasisVector<N> step(std::size_t islice,
168  const HaWpBasisVector<N>& prev_basis,
169  const HaWpBasisVector<N>& curr_basis) const
170  {
171  auto & prev_enum = enumeration_->slice(islice-1);
172  auto & curr_enum = enumeration_->slice(islice);
173  auto & next_enum = enumeration_->slice(islice+1);
174 
175  assert ((int)prev_enum.size() == prev_basis.rows());
176  assert ((int)curr_enum.size() == curr_basis.rows());
177 
178  HaWpBasisVector<N> next_basis(next_enum.size(), npts_);
179 
180  #pragma omp parallel
181  {
182  // pre-allocate
183  CArray<1,N> pr1(1,npts_), pr2(1,npts_);
184 
185  //loop over all multi-indices within next slice [j = position of multi-index within next slice]
186  #pragma omp for
187  for (std::size_t j = 0; j < next_enum.size(); j++) {
188  std::array<int,D> next_index = next_enum[j];
189  //find valid precursor: find first non-zero entry
190  dim_t axis = D;
191  for (dim_t d = 0; d < D; d++) {
192  if (next_index[d] != 0) {
193  axis = d;
194  break;
195  }
196  }
197 
198  assert(axis != D); //assert that multi-index contains some non-zero entries
199 
200 
201  // compute contribution of current slice
202  std::array<int,D> curr_index = next_index;
203  curr_index[axis] -= 1; //get backward neighbour
204  std::size_t curr_ordinal = curr_enum.find(curr_index);
205 
206  assert(curr_ordinal < curr_enum.size()); //assert that multi-index has been found within current slice
207 
208  pr1 = curr_basis.row(curr_ordinal) * Qinv_dx_.row(axis).array() * std::sqrt(2.0)/eps_ ;
209 
210 
211  // compute contribution of previous slice
212  std::array< std::size_t,D > prev_ordinals = prev_enum.find_backward_neighbours(curr_index);
213 
214  pr2.setZero();
215 
216  for (dim_t d = 0; d < D; d++) {
217  if (curr_index[d] != 0) {
218  pr2 += prev_basis.row(prev_ordinals[d]) * Qh_Qinvt_(axis,d) * sqrt_[ curr_index[d] ];
219  }
220  }
221 
222 
223  // compute basis value within next slice
224  next_basis.row(j) = (pr1 - pr2) / sqrt_[ 1+curr_index[axis] ];
225  }
226 
227  }
228  return next_basis;
229  }
230 
239  {
240  HaWpBasisVector<N> complete_basis(enumeration_->n_entries(), npts_);
241  //HaWpBasisVector<N> complete_basis = HaWpBasisVector<N>::Zero(enumeration_->n_entries(), npts_);
242  //~ std::cout << "complete_basis (init):\n" << complete_basis << "\n";
243  //~ std::cout << "complete_basis.shape: " << complete_basis.rows() << ", " << complete_basis.cols() << "\n";
244 
245  HaWpBasisVector<N> prev_basis(0,npts_);
246  HaWpBasisVector<N> curr_basis(0,npts_);
247  HaWpBasisVector<N> next_basis(1,npts_);
248 
249  complete_basis.block(0, 0, 1, npts_) = next_basis = seed();
250 
251  for (int islice = 0; islice < enumeration_->n_slices(); islice++) {
252  prev_basis = std::move(curr_basis);
253  curr_basis = std::move(next_basis);
254 
255  next_basis = step(islice, prev_basis, curr_basis);
256 
257  std::size_t offset = enumeration_->slice(islice+1).offset();
258 
259  //~ std::cout << "offset: " << offset << ", next_basis.rows: " << next_basis.rows() << "\n";
260 
261  complete_basis.block(offset, 0, next_basis.rows(), npts_) = next_basis;
262  }
263 
264  return complete_basis;
265  }
266 
280  CArray<1,N> reduce(const Coefficients& coefficients) const
281  {
282  // use Kahan's algorithm to accumulate bases with O(1) numerical error instead of O(Sqrt(N))
284 
285  HaWpBasisVector<N> prev_basis(0,npts_);
286  HaWpBasisVector<N> curr_basis(0,npts_);
287  HaWpBasisVector<N> next_basis(1,npts_);
288 
289  next_basis = seed();
290 
291  psi += next_basis.row(0)*coefficients[0];
292 
293  for (int islice = 0; islice < enumeration_->n_slices(); islice++) {
294  prev_basis = std::move(curr_basis);
295  curr_basis = std::move(next_basis);
296 
297  next_basis = step(islice, prev_basis, curr_basis);
298 
299  std::size_t offset = enumeration_->slice(islice+1).offset();
300 
301  for (long j = 0; j < next_basis.rows(); j++) {
302  complex_t cj = coefficients[offset + j];
303 
304  //prints: multi-index -> basis -> coefficient
305  //std::cout << enumeration->slice(islice+1)[j] << " -> " << next_basis.row(j).matrix() << " * " << cj << std::endl;
306 
307  psi += next_basis.row(j)*cj;
308  }
309  }
310 
311  return psi();
312  }
313 
329  CArray<Eigen::Dynamic,N> vector_reduce(ShapeEnum<D,MultiIndex> ** subset_enums,
330  complex_t const ** subset_coeffs,
331  std::size_t n_components) const
332  {
333  // use Kahan's algorithm to accumulate bases with O(1) numerical error instead of O(Sqrt(N))
334  std::vector< math::KahanSum< CArray<1,N> > > psi(n_components);
335 
336  HaWpBasisVector<N> prev_basis(0,npts_);
337  HaWpBasisVector<N> curr_basis(0,npts_);
338  HaWpBasisVector<N> next_basis(1,npts_);
339 
340  next_basis = seed();
341 
342  for (std::size_t n = 0; n < n_components; n++) {
343  psi[n] = math::KahanSum< CArray<1,N> >( CArray<1,N>::Zero(1,npts_)); // zero initialize
344  psi[n] += subset_coeffs[n][0]*next_basis.row(0).matrix();
345  }
346 
347  for (int islice = 0; islice < enumeration_->n_slices(); islice++) {
348  prev_basis = std::move(curr_basis);
349  curr_basis = std::move(next_basis);
350 
351  next_basis = step(islice, prev_basis, curr_basis);
352 
353  ShapeSlice<D,MultiIndex> const& superset_slice = enumeration_->slice(islice+1);
354 
355  // for (std::size_t n = 0; n < n_components; n++) {
356  // ShapeSlice<D,MultiIndex> const& subset_slice = subset_enums[n]->slice(islice+1);
357  // HaWpBasisVector<N> subset_basis = shape_enum::copy_subset(next_basis, superset_slice, subset_slice);
358  //
359  // for (long j = 0; j < subset_basis.rows(); j++) {
360  // complex_t cj = subset_coeffs[n][subset_slice.offset() + j];
361  //
362  // psi[n] += cj*subset_basis.row(j);
363  // }
364  // }
365 
366  std::vector<std::size_t> seek(n_components);
367  for (long j = 0; j < next_basis.rows(); j++) {
368  for (std::size_t n = 0; n < n_components; n++) {
369  ShapeSlice<D,MultiIndex> const& subset_slice = subset_enums[n]->slice(islice+1);
370 
371  if (seek[n] < subset_slice.size() && subset_slice[seek[n]] == superset_slice[j]) {
372  complex_t cj = subset_coeffs[n][subset_slice.offset() + seek[n]];
373 
374  psi[n] += next_basis.row(j)*cj;
375 
376  seek[n]++;
377  }
378  }
379  }
380  }
381 
382  CArray<Eigen::Dynamic,N> result(n_components, npts_);
383  for (std::size_t n = 0; n < n_components; n++) {
384  result.row(n) = psi[n]();
385  }
386 
387  return result;
388  }
389 
402  CArray<Eigen::Dynamic,N> vector_reduce(complex_t const ** coefficients, std::size_t n_components) const
403  {
404  // use Kahan's algorithm to accumulate bases with O(1) numerical error instead of O(Sqrt(N))
405  std::vector< math::KahanSum< CArray<1,N> > > psi(n_components);
406 
407  HaWpBasisVector<N> prev_basis(0,npts_);
408  HaWpBasisVector<N> curr_basis(0,npts_);
409  HaWpBasisVector<N> next_basis(1,npts_);
410 
411  next_basis = seed();
412 
413  for (std::size_t n = 0; n < n_components; n++) {
414  psi[n] = math::KahanSum< CArray<1,N> >( CArray<1,N>::Zero(1,npts_)); // zero initialize
415  psi[n] += coefficients[n][0]*next_basis.row(0);
416  }
417 
418  for (int islice = 0; islice < enumeration_->n_slices(); islice++) {
419  prev_basis = std::move(curr_basis);
420  curr_basis = std::move(next_basis);
421 
422  next_basis = step(islice, prev_basis, curr_basis);
423 
424  ShapeSlice<D,MultiIndex> const& slice = enumeration_->slice(islice+1);
425 
426 
427  for (long j = 0; j < next_basis.rows(); j++) {
428  for (std::size_t n = 0; n < n_components; n++) {
429  complex_t cj = coefficients[n][slice.offset() + j];
430 
431  psi[n] += next_basis.row(j)*cj;
432  }
433  }
434  }
435 
436  CArray<Eigen::Dynamic,N> result(n_components, npts_);
437  for (std::size_t n = 0; n < n_components; n++) {
438  result.row(n) = psi[n]();
439  }
440 
441  return result;
442  }
443  };
444  }
445 }
RMatrix< D, 1 > const & p() const
Get the parameter .
Definition: hawp_paramset.hpp:102
Definition: coefficients_file_parser.cpp:10
const HaWpParamSet< D > * parameters_
Definition: hawp_evaluator.hpp:51
function p(by, bw, bv)
Definition: jquery.js:23
Eigen::Matrix< complex_t, D, D > CMatrixDD
Definition: hawp_evaluator.hpp:44
Eigen::Matrix< real_t, R, C > RMatrix
Definition: types.hpp:22
real_t eps_
Definition: hawp_evaluator.hpp:50
Eigen::Matrix< complex_t, Eigen::Dynamic, 1 > Coefficients
Definition: types.hpp:33
const ShapeEnum< D, MultiIndex > * enumeration_
Definition: hawp_evaluator.hpp:52
CMatrix< D, D > const & Q() const
Get the parameter .
Definition: hawp_paramset.hpp:105
std::complex< real_t > complex_t
Definition: types.hpp:15
double real_t
Definition: types.hpp:14
HaWpBasisVector< N > all() const
Evaluates all basis functions.
Definition: hawp_evaluator.hpp:238
CArray< Eigen::Dynamic, N > vector_reduce(ShapeEnum< D, MultiIndex > **subset_enums, complex_t const **subset_coeffs, std::size_t n_components) const
Efficiently evaluates a vectorial wavepacket with shared Hagedorn parameter set, but different basis ...
Definition: hawp_evaluator.hpp:329
Evaluates a wavepacket slice by slice.
Definition: hawp_evaluator.hpp:41
HaWpEvaluator(real_t eps, const HaWpParamSet< D > *parameters, const ShapeEnum< D, MultiIndex > *enumeration, const CMatrixDN &x)
Definition: hawp_evaluator.hpp:93
The Kahan&#39;s algorithm achieves O(1) error growth for summing N numbers.
Definition: kahan_sum.hpp:18
int npts_
Definition: hawp_evaluator.hpp:57
This class represents the Hagedorn parameter set .
Definition: hawp_paramset.hpp:24
CMatrixDN dx_
Definition: hawp_evaluator.hpp:62
Eigen::Matrix< complex_t, D, N > CMatrixDN
Definition: hawp_evaluator.hpp:46
CArray< Eigen::Dynamic, N > HaWpBasisVector
Definition: types.hpp:31
CMatrixDD Qinv_
Definition: hawp_evaluator.hpp:67
CMatrixDN Qinv_dx_
Definition: hawp_evaluator.hpp:77
CMatrix< D, D > const & P() const
Get the parameter .
Definition: hawp_paramset.hpp:108
Eigen::Matrix< real_t, D, N > RMatrixDN
Definition: hawp_evaluator.hpp:47
RMatrix< D, 1 > const & q() const
Get the parameter .
Definition: hawp_paramset.hpp:99
CArray1N seed() const
Evaluates basis function on node (ground-state).
Definition: hawp_evaluator.hpp:130
std::vector< real_t > sqrt_
Definition: hawp_evaluator.hpp:82
Eigen::Matrix< complex_t, R, C > CMatrix
Definition: types.hpp:19
Eigen::Array< complex_t, 1, N > CArray1N
Definition: hawp_evaluator.hpp:45
CArray< Eigen::Dynamic, N > vector_reduce(complex_t const **coefficients, std::size_t n_components) const
Efficiently evaluates a vectorial wavepacket with shared Hagedorn parameter set and shared basis shap...
Definition: hawp_evaluator.hpp:402
CMatrixDD Qh_Qinvt_
Definition: hawp_evaluator.hpp:72
CArray< 1, N > reduce(const Coefficients &coefficients) const
Evaluates wavepacket in a memory efficient manner.
Definition: hawp_evaluator.hpp:280
int dim_t
Definition: types.hpp:16
HaWpBasisVector< N > step(std::size_t islice, const HaWpBasisVector< N > &prev_basis, const HaWpBasisVector< N > &curr_basis) const
Having basis function values on previous and current slice, this member function computes basis funct...
Definition: hawp_evaluator.hpp:167
Eigen::Array< complex_t, R, C > CArray
Definition: types.hpp:25