CMS 3D CMS Logo

LinInterpolatedTableND.h
Go to the documentation of this file.
1 #ifndef NPSTAT_LININTERPOLATEDTABLEND_HH_
2 #define NPSTAT_LININTERPOLATEDTABLEND_HH_
3 
14 #include <climits>
15 #include <vector>
16 #include <utility>
17 
18 #include <memory>
19 
22 
23 namespace npstat {
30  template <class Numeric, class Axis = UniformAxis>
32  template <typename Num2, typename Axis2>
33  friend class LinInterpolatedTableND;
34 
35  public:
36  typedef Numeric value_type;
37  typedef Axis axis_type;
38 
53  LinInterpolatedTableND(const std::vector<Axis>& axes,
54  const std::vector<std::pair<bool, bool> >& extrapolationType,
55  const char* functionLabel = nullptr);
56 
58  LinInterpolatedTableND(const Axis& xAxis, bool leftX, bool rightX, const char* functionLabel = nullptr);
59 
61  LinInterpolatedTableND(const Axis& xAxis,
62  bool leftX,
63  bool rightX,
64  const Axis& yAxis,
65  bool leftY,
66  bool rightY,
67  const char* functionLabel = nullptr);
68 
70  LinInterpolatedTableND(const Axis& xAxis,
71  bool leftX,
72  bool rightX,
73  const Axis& yAxis,
74  bool leftY,
75  bool rightY,
76  const Axis& zAxis,
77  bool leftZ,
78  bool rightZ,
79  const char* functionLabel = nullptr);
80 
82  LinInterpolatedTableND(const Axis& xAxis,
83  bool leftX,
84  bool rightX,
85  const Axis& yAxis,
86  bool leftY,
87  bool rightY,
88  const Axis& zAxis,
89  bool leftZ,
90  bool rightZ,
91  const Axis& tAxis,
92  bool leftT,
93  bool rightT,
94  const char* functionLabel = nullptr);
95 
97  LinInterpolatedTableND(const Axis& xAxis,
98  bool leftX,
99  bool rightX,
100  const Axis& yAxis,
101  bool leftY,
102  bool rightY,
103  const Axis& zAxis,
104  bool leftZ,
105  bool rightZ,
106  const Axis& tAxis,
107  bool leftT,
108  bool rightT,
109  const Axis& vAxis,
110  bool leftV,
111  bool rightV,
112  const char* functionLabel = nullptr);
113 
118  template <class Num2>
120 
122  LinInterpolatedTableND() = delete;
123 
128  Numeric operator()(const double* point, unsigned dim) const;
129 
131 
132  Numeric operator()(const double& x0) const;
133  Numeric operator()(const double& x0, const double& x1) const;
134  Numeric operator()(const double& x0, const double& x1, const double& x2) const;
135  Numeric operator()(const double& x0, const double& x1, const double& x2, const double& x3) const;
136  Numeric operator()(const double& x0, const double& x1, const double& x2, const double& x3, const double& x4) const;
138 
140 
141  inline unsigned dim() const { return dim_; }
142  inline const std::vector<Axis>& axes() const { return axes_; }
143  inline const Axis& axis(const unsigned i) const { return axes_.at(i); }
144  inline unsigned long length() const { return data_.length(); }
145  bool leftInterpolationLinear(unsigned i) const;
146  bool rightInterpolationLinear(unsigned i) const;
147  std::vector<std::pair<bool, bool> > interpolationType() const;
148  inline const std::string& functionLabel() const { return functionLabel_; }
150 
152 
153  inline const ArrayND<Numeric>& table() const { return data_; }
154  inline ArrayND<Numeric>& table() { return data_; }
156 
158  void getCoords(unsigned long linearIndex, double* coords, unsigned coordsBufferSize) const;
159 
164  bool isUniformlyBinned() const;
165 
170  bool isWithinLimits(const double* point, unsigned dim) const;
171 
173  inline void setFunctionLabel(const char* newlabel) { functionLabel_ = newlabel ? newlabel : ""; }
174 
181  template <typename ConvertibleToUnsigned>
182  std::unique_ptr<LinInterpolatedTableND> invertWRTAxis(ConvertibleToUnsigned axisNumber,
183  const Axis& replacementAxis,
184  bool newAxisLeftLinear,
185  bool newAxisRightLinear,
186  const char* functionLabel = nullptr) const;
187 
210  template <class Functor1, class Functor2>
211  std::unique_ptr<LinInterpolatedTableND> invertRatioResponse(unsigned axisNumber,
212  const Axis& replacementAxis,
213  bool newAxisLeftLinear,
214  bool newAxisRightLinear,
215  Functor1 invg,
216  Functor2 invh,
217  const char* functionLabel = nullptr) const;
218 
220  bool operator==(const LinInterpolatedTableND&) const;
221 
223  inline bool operator!=(const LinInterpolatedTableND& r) const { return !(*this == r); }
224 
226  // Method related to "geners" I/O
227  inline gs::ClassId classId() const { return gs::ClassId(*this); }
228  bool write(std::ostream& of) const;
230 
231  static const char* classname();
232  static inline unsigned version() { return 1; }
233  static LinInterpolatedTableND* read(const gs::ClassId& id, std::istream& in);
234 
235  private:
237  const std::vector<Axis>& axes,
238  const char* leftInterpolation,
239  const char* rightInterpolation,
240  const std::string& label);
241 
242  bool allConstInterpolated() const;
243 
245  std::vector<Axis> axes_;
247  char leftInterpolationLinear_[CHAR_BIT * sizeof(unsigned long)];
248  char rightInterpolationLinear_[CHAR_BIT * sizeof(unsigned long)];
249  unsigned dim_;
251 
252  template <class Functor1>
253  static double solveForRatioArg(double xmin, double xmax, double rmin, double rmax, double fval, Functor1 invg);
254 
255  template <class Functor1>
256  static void invert1DResponse(const ArrayND<Numeric>& fromSlice,
257  const Axis& fromAxis,
258  const Axis& toAxis,
259  bool newLeftLinear,
260  bool newRightLinear,
261  Functor1 invg,
262  const double* rawx,
263  const double* rawf,
264  double* workspace,
265  ArrayND<Numeric>* toSlice);
266  };
267 } // namespace npstat
268 
269 #include <cmath>
270 #include <cfloat>
271 #include <cassert>
272 #include <algorithm>
273 #include <functional>
274 
275 #include "Alignment/Geners/interface/binaryIO.hh"
276 
279 
280 namespace npstat {
281  namespace Private {
282  template <class Axis>
283  ArrayShape makeTableShape(const std::vector<Axis>& axes) {
284  const unsigned n = axes.size();
286  result.reserve(n);
287  for (unsigned i = 0; i < n; ++i)
288  result.push_back(axes[i].nCoords());
289  return result;
290  }
291 
292  template <class Axis>
295  result.reserve(1U);
296  result.push_back(xAxis.nCoords());
297  return result;
298  }
299 
300  template <class Axis>
301  ArrayShape makeTableShape(const Axis& xAxis, const Axis& yAxis) {
303  result.reserve(2U);
304  result.push_back(xAxis.nCoords());
305  result.push_back(yAxis.nCoords());
306  return result;
307  }
308 
309  template <class Axis>
310  ArrayShape makeTableShape(const Axis& xAxis, const Axis& yAxis, const Axis& zAxis) {
312  result.reserve(3U);
313  result.push_back(xAxis.nCoords());
314  result.push_back(yAxis.nCoords());
315  result.push_back(zAxis.nCoords());
316  return result;
317  }
318 
319  template <class Axis>
320  ArrayShape makeTableShape(const Axis& xAxis, const Axis& yAxis, const Axis& zAxis, const Axis& tAxis) {
322  result.reserve(4U);
323  result.push_back(xAxis.nCoords());
324  result.push_back(yAxis.nCoords());
325  result.push_back(zAxis.nCoords());
326  result.push_back(tAxis.nCoords());
327  return result;
328  }
329 
330  template <class Axis>
332  const Axis& xAxis, const Axis& yAxis, const Axis& zAxis, const Axis& tAxis, const Axis& vAxis) {
334  result.reserve(5U);
335  result.push_back(xAxis.nCoords());
336  result.push_back(yAxis.nCoords());
337  result.push_back(zAxis.nCoords());
338  result.push_back(tAxis.nCoords());
339  result.push_back(vAxis.nCoords());
340  return result;
341  }
342 
343  inline double lind_interpolateSimple(
344  const double x0, const double x1, const double y0, const double y1, const double x) {
345  return y0 + (y1 - y0) * ((x - x0) / (x1 - x0));
346  }
347 
348  template <typename Numeric, class Axis>
349  void lind_invert1DSlice(const ArrayND<Numeric>& fromSlice,
350  const Axis& fromAxis,
351  const Axis& toAxis,
352  const bool leftLinear,
353  const bool rightLinear,
354  ArrayND<Numeric>* toSlice) {
355  assert(toSlice);
356  assert(fromSlice.rank() == 1U);
357  assert(toSlice->rank() == 1U);
358 
359  const Numeric* fromData = fromSlice.data();
360  const unsigned fromLen = fromSlice.length();
361  assert(fromLen > 1U);
362  assert(fromLen == fromAxis.nCoords());
363  const Numeric* fromDataEnd = fromData + fromLen;
364  if (!isStrictlyMonotonous(fromData, fromDataEnd))
366  "In npstat::Private::lind_invert1DSlice: "
367  "slice data is not monotonous and can not be inverted");
368 
369  const Numeric yfirst = fromData[0];
370  const Numeric ylast = fromData[fromLen - 1U];
371  const bool increasing = yfirst < ylast;
372 
373  Numeric* toD = const_cast<Numeric*>(toSlice->data());
374  const unsigned nAxisPoints = toAxis.nCoords();
375  assert(toSlice->length() == nAxisPoints);
376 
377  for (unsigned ipt = 0; ipt < nAxisPoints; ++ipt) {
378  const Numeric y = static_cast<Numeric>(toAxis.coordinate(ipt));
379  if (increasing) {
380  if (y <= yfirst) {
381  if (leftLinear)
383  yfirst, fromData[1], fromAxis.coordinate(0), fromAxis.coordinate(1), y);
384  else
385  toD[ipt] = fromAxis.coordinate(0);
386  } else if (y >= ylast) {
387  if (rightLinear)
388  toD[ipt] = Private::lind_interpolateSimple(ylast,
389  fromData[fromLen - 2U],
390  fromAxis.coordinate(fromLen - 1U),
391  fromAxis.coordinate(fromLen - 2U),
392  y);
393  else
394  toD[ipt] = fromAxis.coordinate(fromLen - 1U);
395  } else {
396  const unsigned i = std::lower_bound(fromData, fromDataEnd, y) - fromData;
398  fromData[i - 1U], fromData[i], fromAxis.coordinate(i - 1U), fromAxis.coordinate(i), y);
399  }
400  } else {
401  // The role of left and right are exchanged
402  // with respect to first and last point
403  if (y <= ylast) {
404  if (leftLinear)
405  toD[ipt] = Private::lind_interpolateSimple(ylast,
406  fromData[fromLen - 2U],
407  fromAxis.coordinate(fromLen - 1U),
408  fromAxis.coordinate(fromLen - 2U),
409  y);
410  else
411  toD[ipt] = fromAxis.coordinate(fromLen - 1U);
412  } else if (y >= yfirst) {
413  if (rightLinear)
415  yfirst, fromData[1], fromAxis.coordinate(0), fromAxis.coordinate(1), y);
416  else
417  toD[ipt] = fromAxis.coordinate(0);
418  } else {
419  const unsigned i = std::lower_bound(fromData, fromDataEnd, y, std::greater<Numeric>()) - fromData;
421  fromData[i - 1U], fromData[i], fromAxis.coordinate(i - 1U), fromAxis.coordinate(i), y);
422  }
423  }
424  }
425  }
426  } // namespace Private
427 
428  template <class Numeric, class Axis>
430  for (unsigned i = 0; i < dim_; ++i)
431  if (leftInterpolationLinear_[i] || rightInterpolationLinear_[i])
432  return false;
433  return true;
434  }
435 
436  template <class Numeric, class Axis>
438  if (dim_ != r.dim_)
439  return false;
440  for (unsigned i = 0; i < dim_; ++i) {
441  if (leftInterpolationLinear_[i] != r.leftInterpolationLinear_[i])
442  return false;
443  if (rightInterpolationLinear_[i] != r.rightInterpolationLinear_[i])
444  return false;
445  }
446  return data_ == r.data_ && axes_ == r.axes_ && functionLabel_ == r.functionLabel_;
447  }
448 
449  template <typename Numeric, class Axis>
451  static const std::string myClass(gs::template_class_name<Numeric, Axis>("npstat::LinInterpolatedTableND"));
452  return myClass.c_str();
453  }
454 
455  template <typename Numeric, class Axis>
457  const bool status = data_.classId().write(of) && data_.write(of) && gs::write_obj_vector(of, axes_);
458  if (status) {
459  gs::write_pod_array(of, leftInterpolationLinear_, dim_);
460  gs::write_pod_array(of, rightInterpolationLinear_, dim_);
461  gs::write_pod(of, functionLabel_);
462  }
463  return status && !of.fail();
464  }
465 
466  template <typename Numeric, class Axis>
468  std::istream& in) {
469  static const gs::ClassId current(gs::ClassId::makeId<LinInterpolatedTableND<Numeric, Axis> >());
470  current.ensureSameId(id);
471 
472  gs::ClassId ida(in, 1);
475  std::vector<Axis> axes;
476  gs::read_heap_obj_vector_as_placed(in, &axes);
477  const unsigned dim = axes.size();
478  if (dim > CHAR_BIT * sizeof(unsigned long) || data.rank() != dim)
479  throw gs::IOInvalidData(
480  "In npstat::LinInterpolatedTableND::read: "
481  "read back invalid dimensionality");
482  char leftInterpolation[CHAR_BIT * sizeof(unsigned long)];
483  gs::read_pod_array(in, leftInterpolation, dim);
484  char rightInterpolation[CHAR_BIT * sizeof(unsigned long)];
485  gs::read_pod_array(in, rightInterpolation, dim);
487  gs::read_pod(in, &label);
488  if (in.fail())
489  throw gs::IOReadFailure("In npstat::LinInterpolatedTableND::read: input stream failure");
490  return new LinInterpolatedTableND(data, axes, leftInterpolation, rightInterpolation, label);
491  }
492 
493  template <typename Numeric, class Axis>
495  if (i >= dim_)
497  "In npstat::LinInterpolatedTableND::leftInterpolationLinear: "
498  "index out of range");
499  return leftInterpolationLinear_[i];
500  }
501 
502  template <typename Numeric, class Axis>
504  if (i >= dim_)
506  "In npstat::LinInterpolatedTableND::rightInterpolationLinear: "
507  "index out of range");
508  return rightInterpolationLinear_[i];
509  }
510 
511  template <typename Numeric, class Axis>
513  for (unsigned i = 0; i < dim_; ++i)
514  if (!axes_[i].isUniform())
515  return false;
516  return true;
517  }
518 
519  template <typename Numeric, class Axis>
520  std::vector<std::pair<bool, bool> > LinInterpolatedTableND<Numeric, Axis>::interpolationType() const {
521  std::vector<std::pair<bool, bool> > vec;
522  vec.reserve(dim_);
523  for (unsigned i = 0; i < dim_; ++i)
524  vec.push_back(std::pair<bool, bool>(leftInterpolationLinear_[i], rightInterpolationLinear_[i]));
525  return vec;
526  }
527 
528  template <typename Numeric, class Axis>
530  const std::vector<Axis>& axes, const std::vector<std::pair<bool, bool> >& interpolationType, const char* label)
531  : data_(Private::makeTableShape(axes)), axes_(axes), functionLabel_(label ? label : ""), dim_(axes.size()) {
532  if (dim_ == 0 || dim_ >= CHAR_BIT * sizeof(unsigned long))
534  "In npstat::LinInterpolatedTableND constructor: requested "
535  "table dimensionality is not supported");
536  if (dim_ != interpolationType.size())
538  "In npstat::LinInterpolatedTableND constructor: "
539  "incompatible number of interpolation specifications");
540  for (unsigned i = 0; i < dim_; ++i) {
541  const std::pair<bool, bool>& pair(interpolationType[i]);
542  leftInterpolationLinear_[i] = pair.first;
543  rightInterpolationLinear_[i] = pair.second;
544  }
545 
547  }
548 
549  template <typename Numeric, class Axis>
550  template <class Num2>
552  : data_(r.data_),
553  axes_(r.axes_),
554  functionLabel_(r.functionLabel_),
555  dim_(r.dim_),
556  allConstInterpolated_(r.allConstInterpolated_) {
557  for (unsigned i = 0; i < dim_; ++i) {
558  leftInterpolationLinear_[i] = r.leftInterpolationLinear_[i];
559  rightInterpolationLinear_[i] = r.rightInterpolationLinear_[i];
560  }
561  }
562 
563  template <typename Numeric, class Axis>
565  const std::vector<Axis>& axes,
566  const char* leftInterpolation,
567  const char* rightInterpolation,
568  const std::string& label)
569  : data_(data), axes_(axes), functionLabel_(label), dim_(data.rank()) {
570  for (unsigned i = 0; i < dim_; ++i) {
571  leftInterpolationLinear_[i] = leftInterpolation[i];
572  rightInterpolationLinear_[i] = rightInterpolation[i];
573  }
575  }
576 
577  template <typename Numeric, class Axis>
579  bool leftX,
580  bool rightX,
581  const Axis& yAxis,
582  bool leftY,
583  bool rightY,
584  const Axis& zAxis,
585  bool leftZ,
586  bool rightZ,
587  const Axis& tAxis,
588  bool leftT,
589  bool rightT,
590  const Axis& vAxis,
591  bool leftV,
592  bool rightV,
593  const char* label)
594  : data_(Private::makeTableShape(xAxis, yAxis, zAxis, tAxis, vAxis)),
595  functionLabel_(label ? label : ""),
596  dim_(5U) {
597  axes_.reserve(dim_);
598  axes_.push_back(xAxis);
599  axes_.push_back(yAxis);
600  axes_.push_back(zAxis);
601  axes_.push_back(tAxis);
602  axes_.push_back(vAxis);
603 
604  unsigned i = 0;
605  leftInterpolationLinear_[i] = leftX;
606  rightInterpolationLinear_[i++] = rightX;
607  leftInterpolationLinear_[i] = leftY;
608  rightInterpolationLinear_[i++] = rightY;
609  leftInterpolationLinear_[i] = leftZ;
610  rightInterpolationLinear_[i++] = rightZ;
611  leftInterpolationLinear_[i] = leftT;
612  rightInterpolationLinear_[i++] = rightT;
613  leftInterpolationLinear_[i] = leftV;
614  rightInterpolationLinear_[i++] = rightV;
615  assert(i == dim_);
616 
618  }
619 
620  template <typename Numeric, class Axis>
622  bool leftX,
623  bool rightX,
624  const Axis& yAxis,
625  bool leftY,
626  bool rightY,
627  const Axis& zAxis,
628  bool leftZ,
629  bool rightZ,
630  const Axis& tAxis,
631  bool leftT,
632  bool rightT,
633  const char* label)
634  : data_(Private::makeTableShape(xAxis, yAxis, zAxis, tAxis)), functionLabel_(label ? label : ""), dim_(4U) {
635  axes_.reserve(dim_);
636  axes_.push_back(xAxis);
637  axes_.push_back(yAxis);
638  axes_.push_back(zAxis);
639  axes_.push_back(tAxis);
640 
641  unsigned i = 0;
642  leftInterpolationLinear_[i] = leftX;
643  rightInterpolationLinear_[i++] = rightX;
644  leftInterpolationLinear_[i] = leftY;
645  rightInterpolationLinear_[i++] = rightY;
646  leftInterpolationLinear_[i] = leftZ;
647  rightInterpolationLinear_[i++] = rightZ;
648  leftInterpolationLinear_[i] = leftT;
649  rightInterpolationLinear_[i++] = rightT;
650  assert(i == dim_);
651 
653  }
654 
655  template <typename Numeric, class Axis>
657  bool leftX,
658  bool rightX,
659  const Axis& yAxis,
660  bool leftY,
661  bool rightY,
662  const Axis& zAxis,
663  bool leftZ,
664  bool rightZ,
665  const char* label)
666  : data_(Private::makeTableShape(xAxis, yAxis, zAxis)), functionLabel_(label ? label : ""), dim_(3U) {
667  axes_.reserve(dim_);
668  axes_.push_back(xAxis);
669  axes_.push_back(yAxis);
670  axes_.push_back(zAxis);
671 
672  unsigned i = 0;
673  leftInterpolationLinear_[i] = leftX;
674  rightInterpolationLinear_[i++] = rightX;
675  leftInterpolationLinear_[i] = leftY;
676  rightInterpolationLinear_[i++] = rightY;
677  leftInterpolationLinear_[i] = leftZ;
678  rightInterpolationLinear_[i++] = rightZ;
679  assert(i == dim_);
680 
682  }
683 
684  template <typename Numeric, class Axis>
686  const Axis& xAxis, bool leftX, bool rightX, const Axis& yAxis, bool leftY, bool rightY, const char* label)
687  : data_(Private::makeTableShape(xAxis, yAxis)), functionLabel_(label ? label : ""), dim_(2U) {
688  axes_.reserve(dim_);
689  axes_.push_back(xAxis);
690  axes_.push_back(yAxis);
691 
692  unsigned i = 0;
693  leftInterpolationLinear_[i] = leftX;
694  rightInterpolationLinear_[i++] = rightX;
695  leftInterpolationLinear_[i] = leftY;
696  rightInterpolationLinear_[i++] = rightY;
697  assert(i == dim_);
698 
700  }
701 
702  template <typename Numeric, class Axis>
704  bool leftX,
705  bool rightX,
706  const char* label)
707  : data_(Private::makeTableShape(xAxis)), functionLabel_(label ? label : ""), dim_(1U) {
708  axes_.reserve(dim_);
709  axes_.push_back(xAxis);
710 
711  leftInterpolationLinear_[0] = leftX;
712  rightInterpolationLinear_[0] = rightX;
713 
715  }
716 
717  template <typename Numeric, class Axis>
718  template <typename ConvertibleToUnsigned>
719  std::unique_ptr<LinInterpolatedTableND<Numeric, Axis> > LinInterpolatedTableND<Numeric, Axis>::invertWRTAxis(
720  const ConvertibleToUnsigned axisNumC,
721  const Axis& replacementAxis,
722  const bool leftLinear,
723  const bool rightLinear,
724  const char* functionLabel) const {
725  const unsigned axisNumber = static_cast<unsigned>(axisNumC);
726 
727  if (axisNumber >= dim_)
729  "In npstat::LinInterpolatedTableND::invertAxis: "
730  "axis number is out of range");
731 
732  // Generate the new set of axes
733  std::vector<Axis> newAxes(axes_);
734  newAxes[axisNumber] = replacementAxis;
735 
736  std::vector<std::pair<bool, bool> > iType(interpolationType());
737  iType[axisNumber] = std::pair<bool, bool>(leftLinear, rightLinear);
738 
739  // Create the new table
740  std::unique_ptr<LinInterpolatedTableND> pTable(new LinInterpolatedTableND(newAxes, iType, functionLabel));
741 
742  if (dim_ > 1U) {
743  // Prepare array slices
744  unsigned sliceIndex[CHAR_BIT * sizeof(unsigned long)];
745  unsigned fixedIndices[CHAR_BIT * sizeof(unsigned long)];
746  unsigned count = 0;
747  for (unsigned i = 0; i < dim_; ++i)
748  if (i != axisNumber) {
749  sliceIndex[count] = data_.span(i);
750  fixedIndices[count++] = i;
751  }
752  ArrayND<Numeric> parentSlice(data_, fixedIndices, count);
753  ArrayND<Numeric> dauSlice(pTable->data_, fixedIndices, count);
754 
755  // Cycle over the slices
756  for (ArrayNDScanner scan(sliceIndex, count); scan.isValid(); ++scan) {
757  scan.getIndex(sliceIndex, count);
758  data_.exportSlice(&parentSlice, fixedIndices, sliceIndex, count);
760  parentSlice, axes_[axisNumber], replacementAxis, leftLinear, rightLinear, &dauSlice);
761  pTable->data_.importSlice(dauSlice, fixedIndices, sliceIndex, count);
762  }
763  } else
764  Private::lind_invert1DSlice(data_, axes_[0], replacementAxis, leftLinear, rightLinear, &pTable->data_);
765  return pTable;
766  }
767 
768  template <typename Numeric, class Axis>
769  template <class Functor1, class Functor2>
770  std::unique_ptr<LinInterpolatedTableND<Numeric, Axis> > LinInterpolatedTableND<Numeric, Axis>::invertRatioResponse(
771  const unsigned axisNumber,
772  const Axis& replacementAxis,
773  const bool leftLinear,
774  const bool rightLinear,
775  Functor1 invg,
776  Functor2 invh,
777  const char* functionLabel) const {
778  if (axisNumber >= dim_)
780  "In npstat::LinInterpolatedTableND::invertRatioResponse: "
781  "axis number is out of range");
782 
783  // Generate the new set of axes
784  std::vector<Axis> newAxes(axes_);
785  newAxes[axisNumber] = replacementAxis;
786 
787  std::vector<std::pair<bool, bool> > iType(interpolationType());
788  iType[axisNumber] = std::pair<bool, bool>(leftLinear, rightLinear);
789 
790  // Transform the original axis to the raw x values
791  const Axis& oldAxis(axes_[axisNumber]);
792  std::vector<double> rawx;
793  const unsigned nCoords = oldAxis.nCoords();
794  rawx.reserve(nCoords);
795  for (unsigned i = 0; i < nCoords; ++i) {
796  const double x = invg(oldAxis.coordinate(i));
797  if (x < 0.0)
799  "In npstat::LinInterpolatedTableND::invertRatioResponse: "
800  "invalid original axis definition (negative transformed "
801  "coordinate)");
802  rawx.push_back(x);
803  }
804 
805  // Transform the new axis to the raw f(x) values
806  std::vector<double> rawf;
807  const unsigned nFuncs = replacementAxis.nCoords();
808  rawf.reserve(nFuncs);
809  for (unsigned i = 0; i < nFuncs; ++i) {
810  const double f = invh(replacementAxis.coordinate(i));
811  if (f < 0.0)
813  "In npstat::LinInterpolatedTableND::invertRatioResponse: "
814  "invalid new axis definition (negative transformed "
815  "coordinate)");
816  rawf.push_back(f);
817  }
818 
819  // Workspace needed for the inversion code
820  std::vector<double> workspace(nCoords);
821 
822  // Create the new table
823  std::unique_ptr<LinInterpolatedTableND> pTable(new LinInterpolatedTableND(newAxes, iType, functionLabel));
824 
825  if (dim_ > 1U) {
826  // Prepare array slices
827  unsigned sliceIndex[CHAR_BIT * sizeof(unsigned long)];
828  unsigned fixedIndices[CHAR_BIT * sizeof(unsigned long)];
829  unsigned count = 0;
830  for (unsigned i = 0; i < dim_; ++i)
831  if (i != axisNumber) {
832  sliceIndex[count] = data_.span(i);
833  fixedIndices[count++] = i;
834  }
835  ArrayND<Numeric> parentSlice(data_, fixedIndices, count);
836  ArrayND<Numeric> dauSlice(pTable->data_, fixedIndices, count);
837 
838  // Cycle over the slices
839  for (ArrayNDScanner scan(sliceIndex, count); scan.isValid(); ++scan) {
840  scan.getIndex(sliceIndex, count);
841  data_.exportSlice(&parentSlice, fixedIndices, sliceIndex, count);
842  invert1DResponse(parentSlice,
843  oldAxis,
844  replacementAxis,
845  leftLinear,
846  rightLinear,
847  invg,
848  &rawx[0],
849  &rawf[0],
850  &workspace[0],
851  &dauSlice);
852  pTable->data_.importSlice(dauSlice, fixedIndices, sliceIndex, count);
853  }
854  } else
855  invert1DResponse(data_,
856  oldAxis,
857  replacementAxis,
858  leftLinear,
859  rightLinear,
860  invg,
861  &rawx[0],
862  &rawf[0],
863  &workspace[0],
864  &pTable->data_);
865  return pTable;
866  }
867 
868  template <typename Numeric, class Axis>
869  void LinInterpolatedTableND<Numeric, Axis>::getCoords(const unsigned long linearIndex,
870  double* coords,
871  const unsigned coordsBufferSize) const {
872  if (coordsBufferSize < dim_)
874  "In LinInterpolatedTableND::getCoords: "
875  "insufficient buffer size");
876  assert(coords);
877  unsigned index[CHAR_BIT * sizeof(unsigned long)];
878  data_.convertLinearIndex(linearIndex, index, dim_);
879  for (unsigned i = 0; i < dim_; ++i)
880  coords[i] = axes_[i].coordinate(index[i]);
881  }
882 
883  template <typename Numeric, class Axis>
884  bool LinInterpolatedTableND<Numeric, Axis>::isWithinLimits(const double* point, const unsigned len) const {
885  if (len != dim_)
887  "In npstat::LinInterpolatedTableND::isWithinLimits: "
888  "incompatible point dimensionality");
889  assert(point);
890 
891  for (unsigned i = 0; i < dim_; ++i)
892  if (point[i] < axes_[i].min() || point[i] > axes_[i].max())
893  return false;
894  return true;
895  }
896 
897  template <typename Numeric, class Axis>
898  Numeric LinInterpolatedTableND<Numeric, Axis>::operator()(const double* point, const unsigned len) const {
899  typedef typename ProperDblFromCmpl<Numeric>::type proper_double;
900 
901  if (len != dim_)
903  "In npstat::LinInterpolatedTableND::operator(): "
904  "incompatible point dimensionality");
905  assert(point);
906 
907  bool interpolateArray = true;
908  if (!allConstInterpolated_)
909  for (unsigned i = 0; i < dim_; ++i)
910  if ((leftInterpolationLinear_[i] && point[i] < axes_[i].min()) ||
911  (rightInterpolationLinear_[i] && point[i] > axes_[i].max())) {
912  interpolateArray = false;
913  break;
914  }
915 
916  if (interpolateArray) {
917  // Translate coordinates into the array system and
918  // simply use the ArrayND interpolation facilities
919  double buf[CHAR_BIT * sizeof(unsigned long)];
920  for (unsigned i = 0; i < dim_; ++i) {
921  const std::pair<unsigned, double>& pair = axes_[i].getInterval(point[i]);
922  buf[i] = pair.first + 1U - pair.second;
923  }
924  return data_.interpolate1(buf, dim_);
925  } else {
926  unsigned ix[CHAR_BIT * sizeof(unsigned long)];
927  double weight[CHAR_BIT * sizeof(unsigned long)];
928  for (unsigned i = 0; i < dim_; ++i) {
929  const bool linear = (leftInterpolationLinear_[i] && point[i] < axes_[i].min()) ||
930  (rightInterpolationLinear_[i] && point[i] > axes_[i].max());
931  const std::pair<unsigned, double>& pair =
932  linear ? axes_[i].linearInterval(point[i]) : axes_[i].getInterval(point[i]);
933  ix[i] = pair.first;
934  weight[i] = pair.second;
935  }
936 
937  Numeric sum = Numeric();
938  const unsigned long maxcycle = 1UL << dim_;
939  const unsigned long* strides = data_.strides();
940  const Numeric* dat = data_.data();
941  for (unsigned long icycle = 0UL; icycle < maxcycle; ++icycle) {
942  double w = 1.0;
943  unsigned long icell = 0UL;
944  for (unsigned i = 0; i < dim_; ++i) {
945  if (icycle & (1UL << i)) {
946  w *= (1.0 - weight[i]);
947  icell += strides[i] * (ix[i] + 1U);
948  } else {
949  w *= weight[i];
950  icell += strides[i] * ix[i];
951  }
952  }
953  sum += dat[icell] * static_cast<proper_double>(w);
954  }
955  return sum;
956  }
957  }
958 
959  template <typename Numeric, class Axis>
960  Numeric LinInterpolatedTableND<Numeric, Axis>::operator()(const double& x0) const {
961  const unsigned nArgs = 1U;
962  if (dim_ != nArgs)
964  "In npstat::LinInterpolatedTableND::operator(): number of "
965  "arguments, 1, is incompatible with the interpolator dimensionality");
966  double tmp[nArgs];
967  tmp[0] = x0;
968  return operator()(tmp, nArgs);
969  }
970 
971  template <typename Numeric, class Axis>
972  Numeric LinInterpolatedTableND<Numeric, Axis>::operator()(const double& x0, const double& x1) const {
973  const unsigned nArgs = 2U;
974  if (dim_ != nArgs)
976  "In npstat::LinInterpolatedTableND::operator(): number of "
977  "arguments, 2, is incompatible with the interpolator dimensionality");
978  double tmp[nArgs];
979  tmp[0] = x0;
980  tmp[1] = x1;
981  return operator()(tmp, nArgs);
982  }
983 
984  template <typename Numeric, class Axis>
986  const double& x1,
987  const double& x2) const {
988  const unsigned nArgs = 3U;
989  if (dim_ != nArgs)
991  "In npstat::LinInterpolatedTableND::operator(): number of "
992  "arguments, 3, is incompatible with the interpolator dimensionality");
993  double tmp[nArgs];
994  tmp[0] = x0;
995  tmp[1] = x1;
996  tmp[2] = x2;
997  return operator()(tmp, nArgs);
998  }
999 
1000  template <typename Numeric, class Axis>
1002  const double& x1,
1003  const double& x2,
1004  const double& x3) const {
1005  const unsigned nArgs = 4U;
1006  if (dim_ != nArgs)
1008  "In npstat::LinInterpolatedTableND::operator(): number of "
1009  "arguments, 4, is incompatible with the interpolator dimensionality");
1010  double tmp[nArgs];
1011  tmp[0] = x0;
1012  tmp[1] = x1;
1013  tmp[2] = x2;
1014  tmp[3] = x3;
1015  return operator()(tmp, nArgs);
1016  }
1017 
1018  template <typename Numeric, class Axis>
1020  const double& x0, const double& x1, const double& x2, const double& x3, const double& x4) const {
1021  const unsigned nArgs = 5U;
1022  if (dim_ != nArgs)
1024  "In npstat::LinInterpolatedTableND::operator(): number of "
1025  "arguments, 5, is incompatible with the interpolator dimensionality");
1026  double tmp[nArgs];
1027  tmp[0] = x0;
1028  tmp[1] = x1;
1029  tmp[2] = x2;
1030  tmp[3] = x3;
1031  tmp[4] = x4;
1032  return operator()(tmp, nArgs);
1033  }
1034 
1035  template <typename Numeric, class Axis>
1036  template <class Functor1>
1038  const double xmin, const double xmax, const double rmin, const double rmax, const double fval, Functor1 invg) {
1039  // Find two values of x so that f(x0) <= fval <= f(x1)
1040  double x0 = xmin;
1041  double x1 = xmax;
1042  double fmin = invg(xmin) * rmin;
1043  double fmax = invg(xmax) * rmax;
1044  const double step = xmax - xmin;
1045  assert(fmin < fmax);
1046  assert(step > 0.0);
1047 
1048  unsigned stepcount = 0;
1049  const unsigned maxSteps = 1000U;
1050  for (double stepfactor = 1.0; (fval < fmin || fval > fmax) && stepcount < maxSteps; stepfactor *= 2.0, ++stepcount)
1051  if (fval < fmin) {
1052  x1 = x0;
1053  fmax = fmin;
1054  x0 -= stepfactor * step;
1055  fmin = invg(x0) * Private::lind_interpolateSimple(xmin, xmax, rmin, rmax, x0);
1056  } else {
1057  x0 = x1;
1058  fmin = fmax;
1059  x1 += stepfactor * step;
1060  fmax = invg(x1) * Private::lind_interpolateSimple(xmin, xmax, rmin, rmax, x1);
1061  }
1062  if (stepcount == maxSteps)
1064  "In LinInterpolatedTableND::solveForRatioArg: "
1065  "faled to bracket the root");
1066 
1067  assert(x1 >= x0);
1068  while ((x1 - x0) / (std::abs(x1) + std::abs(x0) + DBL_EPSILON) > 4.0 * DBL_EPSILON) {
1069  const double xhalf = (x1 + x0) / 2.0;
1070  const double fhalf = invg(xhalf) * Private::lind_interpolateSimple(xmin, xmax, rmin, rmax, xhalf);
1071  if (fval < fhalf) {
1072  x1 = xhalf;
1073  fmax = fhalf;
1074  } else {
1075  x0 = xhalf;
1076  fmin = fhalf;
1077  }
1078  }
1079  return (x1 + x0) / 2.0;
1080  }
1081 
1082  template <typename Numeric, class Axis>
1083  template <class Functor1>
1085  const Axis& fromAxis,
1086  const Axis& toAxis,
1087  const bool newLeftLinear,
1088  const bool newRightLinear,
1089  Functor1 invg,
1090  const double* rawx,
1091  const double* rawf,
1092  double* workspace,
1093  ArrayND<Numeric>* toSlice) {
1094  assert(toSlice);
1095  assert(fromSlice.rank() == 1U);
1096  assert(toSlice->rank() == 1U);
1097 
1098  const Numeric zero = Numeric();
1099  const Numeric* fromData = fromSlice.data();
1100  const unsigned fromLen = fromSlice.length();
1101  assert(fromLen > 1U);
1102  assert(fromLen == fromAxis.nCoords());
1103  Numeric* toD = const_cast<Numeric*>(toSlice->data());
1104  const unsigned nAxisPoints = toAxis.nCoords();
1105  assert(toSlice->length() == nAxisPoints);
1106 
1107  for (unsigned i = 0; i < fromLen; ++i) {
1108  if (fromData[i] <= zero)
1110  "In LinInterpolatedTableND::invert1DResponse: "
1111  "non-positive response found. This ratio "
1112  "response table is not invertible.");
1113  workspace[i] = rawx[i] * fromData[i];
1114  }
1115 
1116  const double yfirst = workspace[0];
1117  const double ylast = workspace[fromLen - 1U];
1118 
1119  bool adjustZero = false;
1120  unsigned nBelow = 0;
1121  for (unsigned ipt = 0; ipt < nAxisPoints; ++ipt) {
1122  const double y = rawf[ipt];
1123  unsigned i0 = 0;
1124  bool solve = false;
1125  if (y == 0.0) {
1126  assert(ipt == 0U);
1127  if (newLeftLinear)
1128  adjustZero = true;
1129  } else if (y <= yfirst) {
1130  ++nBelow;
1131  solve = newLeftLinear;
1132  } else if (y >= ylast) {
1133  solve = newRightLinear;
1134  i0 = solve ? fromLen - 2 : fromLen - 1;
1135  } else {
1136  solve = true;
1137  i0 = static_cast<unsigned>(std::lower_bound(workspace, workspace + fromLen, y) - workspace) - 1U;
1138  }
1139  if (solve) {
1140  const double x = solveForRatioArg(
1141  fromAxis.coordinate(i0), fromAxis.coordinate(i0 + 1), fromData[i0], fromData[i0 + 1], y, invg);
1142  toD[ipt] = invg(x) / y;
1143  } else
1144  toD[ipt] = 1.0 / fromData[i0];
1145  }
1146  if (adjustZero && nBelow)
1147  toD[0] = toD[1];
1148  }
1149 } // namespace npstat
1150 
1151 #endif // NPSTAT_LININTERPOLATEDTABLEND_HH_
bool leftInterpolationLinear(unsigned i) const
const ArrayND< Numeric > & table() const
Uniformly spaced coordinate sets for use in constructing rectangular grids.
static void invert1DResponse(const ArrayND< Numeric > &fromSlice, const Axis &fromAxis, const Axis &toAxis, bool newLeftLinear, bool newRightLinear, Functor1 invg, const double *rawx, const double *rawf, double *workspace, ArrayND< Numeric > *toSlice)
T w() const
Numeric operator()(const double *point, unsigned dim) const
std::unique_ptr< LinInterpolatedTableND > invertWRTAxis(ConvertibleToUnsigned axisNumber, const Axis &replacementAxis, bool newAxisLeftLinear, bool newAxisRightLinear, const char *functionLabel=nullptr) const
const std::vector< Axis > & axes() const
Definition: weight.py:1
void getCoords(unsigned long linearIndex, double *coords, unsigned coordsBufferSize) const
std::vector< unsigned > ArrayShape
Definition: ArrayShape.h:21
assert(be >=bs)
std::unique_ptr< LinInterpolatedTableND > invertRatioResponse(unsigned axisNumber, const Axis &replacementAxis, bool newAxisLeftLinear, bool newAxisRightLinear, Functor1 invg, Functor2 invh, const char *functionLabel=nullptr) const
const Numeric * data() const
Definition: ArrayND.h:236
static double solveForRatioArg(double xmin, double xmax, double rmin, double rmax, double fval, Functor1 invg)
char const * label
A few simple template functions for checking monotonicity of container values.
bool rightInterpolationLinear(unsigned i) const
bool operator!=(const LinInterpolatedTableND &r) const
static LinInterpolatedTableND * read(const gs::ClassId &id, std::istream &in)
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
double f[11][100]
void setFunctionLabel(const char *newlabel)
char rightInterpolationLinear_[CHAR_BIT *sizeof(unsigned long)]
ArrayShape makeTableShape(const Axis &xAxis, const Axis &yAxis, const Axis &zAxis, const Axis &tAxis, const Axis &vAxis)
char leftInterpolationLinear_[CHAR_BIT *sizeof(unsigned long)]
double lind_interpolateSimple(const double x0, const double x1, const double y0, const double y1, const double x)
ALPAKA_FN_ACC ALPAKA_FN_INLINE uint32_t ix(uint32_t id)
bool isStrictlyMonotonous(Iter const begin, Iter const end)
Definition: isMonotonous.h:44
static void restore(const gs::ClassId &id, std::istream &in, ArrayND *array)
Definition: ArrayND.h:5386
bool operator==(const LinInterpolatedTableND &) const
ArrayShape makeTableShape(const std::vector< Axis > &axes)
void lind_invert1DSlice(const ArrayND< Numeric > &fromSlice, const Axis &fromAxis, const Axis &toAxis, const bool leftLinear, const bool rightLinear, ArrayND< Numeric > *toSlice)
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:80
unsigned long length() const
Definition: ArrayND.h:233
float x
const std::string & functionLabel() const
std::vector< std::pair< bool, bool > > interpolationType() const
step
Definition: StallMonitor.cc:83
float linear(float x)
const Axis & axis(const unsigned i) const
Iteration over indices of a multidimensional array.
tmp
align.sh
Definition: createJobs.py:716
unsigned rank() const
Definition: ArrayND.h:242
bool isWithinLimits(const double *point, unsigned dim) const
bool write(std::ostream &of) const
Arbitrary-dimensional array template.
*vegas h *****************************************************used in the default bin number in original ***version of VEGAS is ***a higher bin number might help to derive a more precise ***grade subtle point
Definition: invegas.h:5