npstat is hosted by Hepforge, IPPP Durham
NPStat  5.10.0
ArrayND.hh
Go to the documentation of this file.
1 #ifndef NPSTAT_ARRAYND_HH_
2 #define NPSTAT_ARRAYND_HH_
3 
4 /*!
5 // \file ArrayND.hh
6 //
7 // \brief Arbitrary-dimensional array template
8 //
9 // Author: I. Volobouev
10 //
11 // October 2009
12 */
13 
14 #include <vector>
15 #include <cassert>
16 #include <utility>
17 
18 #include "geners/ClassId.hh"
19 #include "geners/CPP11_auto_ptr.hh"
20 
22 #include "npstat/nm/ArrayRange.hh"
24 #include "npstat/nm/AbsVisitor.hh"
25 #include "npstat/nm/LongerType.hh"
26 #include "npstat/nm/PreciseType.hh"
28 
29 namespace npstat {
30  template <typename Numeric, unsigned StackLen=1U, unsigned StackDim=10U>
31  class ArrayND;
32 }
33 
34 //@{
35 /** Element-wise arithmetic operator */
36 template <typename Numeric, unsigned StackLen, unsigned StackDim,
37  typename Num2, unsigned Len2, unsigned Dim2>
43 
44 template <typename Numeric, unsigned StackLen, unsigned StackDim,
45  typename Num2, unsigned Len2, unsigned Dim2>
51 
52 template <typename Numeric, unsigned StackLen, unsigned StackDim,
53  typename Num2, unsigned Len2, unsigned Dim2>
59 
60 template <typename Numeric, unsigned StackLen, unsigned StackDim,
61  typename Num2, unsigned Len2, unsigned Dim2>
67 //@}
68 
69 namespace npstat {
70  /**
71  // A class for multidimensional array manipulation. A number of methods
72  // of this class will work only if dimensionality is limited by
73  // CHAR_BIT*sizeof(unsigned long)-1 (which is 31 and 63 on 32- and 64-bit
74  // architectures, respectively).
75  //
76  // Depending on how much space is provided with the "StackLen" template
77  // parameter, the array data will be placed either on the stack or on the
78  // heap. By default, array data leaves on the heap unless the array has
79  // rank 0.
80  //
81  // Depending on how much space is provided with the "StackDim" template
82  // parameter, the array strides will be placed either on the stack or
83  // on the heap. By default, strides will be placed on the stack in case
84  // the array dimensionality is ten or less.
85  //
86  // The "Numeric" type must have a default constructor (of course,
87  // pointers to arbitrary types can be used as well).
88  //
89  // Both StackLen and StackDim parameters must be positive.
90  */
91  template <typename Numeric, unsigned StackLen, unsigned StackDim>
92  class ArrayND
93  {
94  template <typename Num2, unsigned Len2, unsigned Dim2>
95  friend class ArrayND;
96 
97  public:
98  typedef Numeric value_type;
99  typedef typename ProperDblFromCmpl<Numeric>::type proper_double;
100 
101  /**
102  // Default constructor creates an uninitialized array. The
103  // following things can be done safely with such an array:
104  //
105  // 1) Assigning it from another array (initialized or not).
106  //
107  // 2) Passing it as an argument to the class static method "restore".
108  //
109  // 3) Calling the "uninitialize" method.
110  //
111  // 4) Calling the "isShapeKnown" method.
112  //
113  // 5) Calling the "reshape" method.
114  //
115  // Any other operation results in an undefined behavior (often,
116  // an exception is thrown). Note that initialized array can not
117  // be assigned from uninitialized one.
118  */
120 
121  /**
122  // Constructor which creates arrays with the given shape.
123  // The array data remains undefined. Simple inilitalization
124  // of the data can be performed using methods clear() or
125  // constFill(SomeValue). More complicated initialization
126  // can be done by "linearFill", "functorFill", or by setting
127  // every array element to a desired value.
128  */
129  explicit ArrayND(const ArrayShape& shape);
130  ArrayND(const unsigned* shape, unsigned dim);
131 
132  /** The copy constructor */
133  ArrayND(const ArrayND&);
134 
135  /** The move constructor */
137 
138  /**
139  // Converting constructor. It looks more general than the copy
140  // constructor, but the actual copy constructor has to be created
141  // anyway -- otherwise the compiler will generate an incorrect
142  // default copy constructor. Note that existence of this
143  // constructor essentially disables data type safety for copying
144  // arrays -- but the code significantly gains in convenience.
145  */
146  template <typename Num2, unsigned Len2, unsigned Dim2>
148 
149  /**
150  // Converting constructor where the array values are filled
151  // by a functor using values of another array as arguments
152  */
153  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
154  ArrayND(const ArrayND<Num2, Len2, Dim2>&, Functor f);
155 
156  /** Constructor from a subrange of another array */
157  template <typename Num2, unsigned Len2, unsigned Dim2>
159  const ArrayRange& fromRange);
160 
161  /** Similar constructor with a transforming functor */
162  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
164  const ArrayRange& fromRange, Functor f);
165 
166  /**
167  // Constructor from a slice of another array. The data of the
168  // constructed array remains undefined. The argument "indices"
169  // lists either the array indices whose numbers will be fixed
170  // when slicing is performed or the indices which will be iterated
171  // over during projections (for example, array values may be
172  // summed over these indices). These indices will be excluded
173  // from the constructed array. The created array can be subsequently
174  // used with methods "exportSlice", "importSlice", "project", etc.
175  // of the parent array "slicedArray".
176  */
177  template <typename Num2, unsigned Len2, unsigned Dim2>
178  ArrayND(const ArrayND<Num2, Len2, Dim2>& slicedArray,
179  const unsigned* indices, unsigned nIndices);
180 
181  /** Outer product constructor */
182  template <typename Num1, unsigned Len1, unsigned Dim1,
183  typename Num2, unsigned Len2, unsigned Dim2>
185  const ArrayND<Num2, Len2, Dim2>& a2);
186 
187  //@{
188  /**
189  // Constructor in which the spans are explicitly provided
190  // for each dimension. The array data remains undefined.
191  */
192  explicit ArrayND(unsigned n0);
193  ArrayND(unsigned n0, unsigned n1);
194  ArrayND(unsigned n0, unsigned n1, unsigned n2);
195  ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3);
196  ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
197  unsigned n4);
198  ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
199  unsigned n4, unsigned n5);
200  ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
201  unsigned n4, unsigned n5, unsigned n6);
202  ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
203  unsigned n4, unsigned n5, unsigned n6, unsigned n7);
204  ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
205  unsigned n4, unsigned n5, unsigned n6, unsigned n7,
206  unsigned n8);
207  ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
208  unsigned n4, unsigned n5, unsigned n6, unsigned n7,
209  unsigned n8, unsigned n9);
210  //@}
211 
212  /** Destructor */
214 
215  /**
216  // Assignment operator. The shape of the array on the right
217  // must be compatible with the shape of the array on the left.
218  // The only exception is when the array on the left has no shape
219  // at all (i.e., it was created by the default constructor or
220  // its "uninitialize" method was called). In this case the array
221  // on the left will assume the shape of the array on the right.
222  */
224 
225  /** The move assignment operator */
227 
228  /** Converting assignment operator */
229  template <typename Num2, unsigned Len2, unsigned Dim2>
231 
232  /** Converting assignment method with a transforming functor */
233  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
235 
236  /**
237  // The function which can "uninitialize" the array to the same
238  // state as produced by the default constructor. Can be applied
239  // in order to force the assignment operators to work.
240  */
242 
243  //@{
244  /** Change the array shape. All data is lost in the process. */
245  ArrayND& reshape(const ArrayShape& newShape);
246  ArrayND& reshape(const unsigned* newShape, unsigned dim);
247  ArrayND& reshape(unsigned n0);
248  ArrayND& reshape(unsigned n0, unsigned n1);
249  ArrayND& reshape(unsigned n0, unsigned n1, unsigned n2);
250  ArrayND& reshape(unsigned n0, unsigned n1, unsigned n2, unsigned n3);
251  ArrayND& reshape(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
252  unsigned n4);
253  ArrayND& reshape(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
254  unsigned n4, unsigned n5);
255  ArrayND& reshape(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
256  unsigned n4, unsigned n5, unsigned n6);
257  ArrayND& reshape(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
258  unsigned n4, unsigned n5, unsigned n6, unsigned n7);
259  ArrayND& reshape(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
260  unsigned n4, unsigned n5, unsigned n6, unsigned n7,
261  unsigned n8);
262  ArrayND& reshape(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
263  unsigned n4, unsigned n5, unsigned n6, unsigned n7,
264  unsigned n8, unsigned n9);
265  //@}
266 
267  /**
268  // Change the shape of this array to be identical to the shape of
269  // the argument array. The shape of the argument array must be known.
270  // All data is lost in the process.
271  */
272  template <typename Num2, unsigned Len2, unsigned Dim2>
274 
275  /**
276  // Element access using multidimensional array index
277  // (no bounds checking). The length of the index array
278  // must be equal to the rank of this object.
279  */
280  Numeric& value(const unsigned* index, unsigned indexLen);
281  const Numeric& value(const unsigned* index, unsigned indexLen) const;
282 
283  /**
284  // Element access using multidimensional array index
285  // (with bounds checking)
286  */
287  Numeric& valueAt(const unsigned* index, unsigned indexLen);
288  const Numeric& valueAt(const unsigned* index, unsigned indexLen) const;
289 
290  /** Element access using linear index (no bounds checking) */
291  Numeric& linearValue(unsigned long index);
292  const Numeric& linearValue(unsigned long index) const;
293 
294  /** Element access using linear index (with bounds checking) */
295  Numeric& linearValueAt(unsigned long index);
296  const Numeric& linearValueAt(unsigned long index) const;
297 
298  /** Convert linear index into multidimensional index */
299  void convertLinearIndex(unsigned long l, unsigned* index,
300  unsigned indexLen) const;
301 
302  inline ArrayShape convertLinearIndex(unsigned long l) const
303  {
304  ArrayShape sh(dim_);
305  if (dim_) this->convertLinearIndex(l, &sh[0], dim_);
306  return sh;
307  }
308 
309  /** The range which encloses all non-zero values of the array */
311 
312  /** Convert multidimensional index into linear index */
313  unsigned long linearIndex(const unsigned* idx, unsigned idxLen) const;
314 
315  inline unsigned long linearIndex(const ArrayShape& sh) const
316  {return linearIndex(sh.empty() ? (unsigned*)0 : &sh[0], sh.size());}
317 
318  // Some inspectors
319  /** Total number of data array elements */
320  inline unsigned long length() const {return len_;}
321 
322  /** Linearized data */
323  inline const Numeric* data() const {return data_;}
324 
325  /** Check whether the array has been initialized */
326  inline bool isShapeKnown() const {return shapeIsKnown_;}
327 
328  /** The number of array dimensions */
329  inline unsigned rank() const {return dim_;}
330 
331  /** Get the complete shape */
332  ArrayShape shape() const;
333 
334  /** Shape data as a C-style array */
335  inline const unsigned* shapeData() const {return shape_;}
336 
337  /** Get the complete range */
339 
340  /** Get the number of elements in some particular dimension */
341  unsigned span(unsigned dim) const;
342 
343  /** Maximum span among all dimensions */
344  unsigned maximumSpan() const;
345 
346  /** Minimum span among all dimensions */
347  unsigned minimumSpan() const;
348 
349  /** Get the strides */
350  inline const unsigned long* strides() const {return strides_;}
351 
352  /** Check if all array elements are zero */
353  bool isZero() const;
354 
355  /** Check if all array elements are non-zero */
356  bool isNonZero() const;
357 
358  /** This method modifies all the data in one statement */
359  template <typename Num2>
360  ArrayND& setData(const Num2* data, unsigned long dataLength);
361 
362  /** Compare two arrays for equality */
363  template <unsigned Len2, unsigned Dim2>
365 
366  /** Logical negation of operator== */
367  template <unsigned Len2, unsigned Dim2>
369 
370  /** Largest absolute difference with another bin-compatible array */
371  template <unsigned Len2, unsigned Dim2>
373 
374  /** Unary operator+ returns a copy of this array */
376 
377  /** multiplication by a scalar */
378  template <typename Num2>
379  ArrayND operator*(const Num2& r) const;
380 
381  /** division by a scalar */
382  template <typename Num2>
383  ArrayND operator/(const Num2& r) const;
384 
385  //@{
386  /**
387  // In-place operator. Note that it works faster than the binary
388  // version with assignment, i.e., A += B is faster than A = A + B.
389  */
390  template <typename Num2>
391  ArrayND& operator*=(const Num2& r);
392 
393  template <typename Num2>
394  ArrayND& operator/=(const Num2& r);
395 
396  template <typename Num2, unsigned Len2, unsigned Dim2>
397  ArrayND& operator+=(const ArrayND<Num2,Len2,Dim2>& r);
398 
399  template <typename Num2, unsigned Len2, unsigned Dim2>
400  ArrayND& operator-=(const ArrayND<Num2,Len2,Dim2>& r);
401 
402  template <typename Num2, unsigned Len2, unsigned Dim2>
404 
405  template <typename Num2, unsigned Len2, unsigned Dim2>
406  ArrayND& operator/=(const ArrayND<Num2,Len2,Dim2>& r);
407  //@}
408 
409  /** This method is equivalent to (but faster than) += r*c */
410  template <typename Num3, typename Num2, unsigned Len2, unsigned Dim2>
411  ArrayND& addmul(const ArrayND<Num2,Len2,Dim2>& r, const Num3& c);
412 
413  /** Outer product as a method (see also the outer product constructor) */
414  template <typename Num2, unsigned Len2, unsigned Dim2>
416 
417  /**
418  // Contraction of a pair of indices. Note that the array length
419  // must be the same in both dimensions.
420  */
421  ArrayND contract(unsigned pos1, unsigned pos2) const;
422 
423  /**
424  // Here, dot product corresponds to outer product followed
425  // by the contraction over two indices -- the last index
426  // of this object and the first index of the argument.
427  */
428  template <typename Num2, unsigned Len2, unsigned Dim2>
430 
431  /**
432  // The intent of this method is to marginalize
433  // over a set of indices with a prior. Essentially, we are
434  // calculating integrals akin to p(y) = Integral f(y|x) g(x) dx
435  // in which all functions are represented on an equidistant grid.
436  // If needed, multiplication of the result by the grid cell size
437  // should be performed after this function. "indexMap" specifies
438  // how the indices of the prior array (which is like g(x)) are
439  // mapped into the indices of this array (which is like f(y|x)).
440  // The number of elements in the map, "mapLen", must be equal to
441  // the rank of the prior. Dimension 0 of the prior corresponds
442  // to the dimension indexMap[0] of this array, dimension 1
443  // corresponds to indexMap[1], etc.
444  */
445  template <typename Num2, unsigned Len2, unsigned Dim2>
447  const unsigned* indexMap, unsigned mapLen) const;
448 
449  /** Transposed array */
450  ArrayND transpose(unsigned pos1, unsigned pos2) const;
451 
452  /** Transpose without arguments can be invoked for 2-d arrays only */
454 
455  /**
456  // Sum of all array elements which uses Num2 type as accumulator.
457  // Typically, the precision and dynamic range of Num2 should be
458  // suitably larger than the precision and dynamic range of Numeric.
459  // For example, if Numeric is float then Num2 should be double, etc.
460  */
461  template <typename Num2 = typename PreciseType<Numeric>::type>
462  Num2 sum() const;
463 
464  /**
465  // Sum of absolute values squared which uses Num2 as accumulator.
466  // Function std::abs(Numeric) must exist.
467  */
468  template <typename Num2 = typename PreciseType<Numeric>::type>
469  Num2 sumsq() const;
470 
471  /**
472  // Mixed derivative over all directions. Useful for generating
473  // densities from distribution functions. The resulting array
474  // will have one less point in each dimension. Class Num2 is
475  // used as accumulator for calculations. static_cast from
476  // Num2 to Numeric must exist. The result is multiplied by the
477  // scale factor provided.
478  */
479  template <typename Num2 = typename PreciseType<Numeric>::type>
480  ArrayND derivative(double scale=1.0) const;
481 
482  /**
483  // The operation inverse to "derivative". Constructs multivariate
484  // cumulative density function.
485  */
486  template <typename Num2 = typename PreciseType<Numeric>::type>
487  ArrayND cdfArray(double scale=1.0) const;
488 
489  /**
490  // Calculate just one multivariate cumulative density function
491  // value. Point with given index will be included in the sum.
492  */
493  template <typename Num2 = typename PreciseType<Numeric>::type>
494  Num2 cdfValue(const unsigned* index, unsigned indexLen) const;
495 
496  /**
497  // The next function turns the array data into the conditional
498  // cumulative density function for the last dimension. "Num2"
499  // is the type of accumulator class used. The cdf is stored
500  // in such a way that the cdf value of 0 is skipped (the first
501  // stored value is the sum which includes the 0th bin). The slice
502  // is filled with the sum of values. The "useTrapezoids" parameter
503  // specifies whether trapezoidal integration formula should be
504  // utilized (rectangular integration is used in case
505  // "useTrapezoids" value is "false").
506  */
507  template <typename Num2 = typename PreciseType<Numeric>::type>
508  void convertToLastDimCdf(ArrayND* sumSlice, bool useTrapezoids);
509 
510  /**
511  // Coarsen this array by summing n nearby elements along
512  // the given dimension. The "result" array will have n
513  // times less elements along that dimension.
514  */
515  template <typename Num2, unsigned Len2, unsigned Dim2>
516  void coarseSum(unsigned idim, unsigned n,
517  ArrayND<Num2,Len2,Dim2>* result) const;
518 
519  /**
520  // Coarsen this array by averaging n nearby elements along
521  // the given dimension. The "result" array will have n
522  // times less elements along that dimension.
523  */
524  template <typename Num2, unsigned Len2, unsigned Dim2>
525  void coarseAverage(unsigned idim, unsigned n,
526  ArrayND<Num2,Len2,Dim2>* result) const;
527 
528  /**
529  // Closest value accessor (works as if the array allows access
530  // with non-integer indices). For example, the second point
531  // in some dimension will be accessed in case the coordinate
532  // in that dimension is between 0.5 and 1.5. This function can be
533  // used, for example, for implementing simple N-D histogramming
534  // or for closest value interpolation and extrapolation.
535  */
536  Numeric& closest(const double* x, unsigned xDim);
537  const Numeric& closest(const double* x, unsigned xDim) const;
538 
539  /**
540  // Multilinear interpolation. Closest value extrapolation is used
541  // in case some index is outside of the array bounds. Note that
542  // this function works only if the array dimensionality is less
543  // than CHAR_BIT*sizeof(unsigned long). x is the "coordinate"
544  // which coincides with array index for x equal to unsigned
545  // integers.
546  */
547  Numeric interpolate1(const double* x, unsigned xDim) const;
548 
549  /**
550  // Multicubic interpolation. Closest value extrapolation is used
551  // in case some index is outside of the array bounds. This
552  // function is much slower than "interpolate1" (in the current
553  // implementation, a recursive algorithm is used).
554  */
555  Numeric interpolate3(const double* x, unsigned xDim) const;
556 
557  /**
558  // This method applies a single-argument functor to each
559  // element of the array (in-place). The result returned
560  // by the functor becomes the new value of the element. There
561  // must be a conversion (static cast) from the functor result to
562  // the "Numeric" type. The method returns *this which allows
563  // for chaining of such methods. Use the transforming constructor
564  // if you want a new array instead.
565  */
566  template <class Functor>
567  ArrayND& apply(Functor f);
568 
569  /**
570  // This method applies a single-argument functor to each
571  // element of the array. The result returned by the functor
572  // is ignored inside the scan. Depending on what the functor does,
573  // the array values may or may not be modified (they can be modified
574  // if the functor takes its argument via a non-const reference).
575  */
576  template <class Functor>
577  ArrayND& scanInPlace(Functor f);
578 
579  /** This method fills the array data with a constant value */
580  ArrayND& constFill(Numeric c);
581 
582  /** Zero the array out (every datum becomes Numeric()) */
584 
585  /**
586  // This method fills the array with a linear combination
587  // of the index values. For example, a 2-d array element with indices
588  // i, k will be set to (coeff[0]*i + coeff[1]*k + c). There must be
589  // a conversion (static cast) from double into "Numeric".
590  */
591  ArrayND& linearFill(const double* coeff, unsigned coeffLen, double c);
592 
593  /**
594  // This method fills the array from a functor
595  // which takes (const unsigned* index, unsigned indexLen)
596  // arguments. There must be a conversion (static cast) from
597  // the functor result to the "Numeric" type.
598  */
599  template <class Functor>
600  ArrayND& functorFill(Functor f);
601 
602  /**
603  // This method can be used for arrays with rank
604  // of at least 2 whose length is the same in all dimensions.
605  // It puts static_cast<Numeric>(1) on the main diagonal and
606  // Numeric() everywhere else.
607  */
609 
610  /** This method turns all negative elements into zeros */
612 
613  /**
614  // This method accumulates marginals and divides
615  // the array (treated as a distribution) by the product of the
616  // marginals. Several iterations like this turn the distribution
617  // into a copula. If the array contains negative elements, they
618  // are turned into zeros before the iterations are performed.
619  // The function returns the actual number of iteration performed
620  // when the given tolerance was reached for all marginals.
621  */
622  unsigned makeCopulaSteps(double tolerance, unsigned maxIterations);
623 
624  /**
625  // Loop over all elements of two compatible arrays and apply
626  // a binary functor
627  */
628  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
629  void jointScan(ArrayND<Num2, Len2, Dim2>& other, Functor binaryFunct);
630 
631  /**
632  // Loop over subranges in two arrays in such a way that the functor
633  // is called only if the indices on both sides are valid. The topology
634  // of both arrays is assumed to be box-like (flat). The starting
635  // corner in this object (where cycling begins) is provided by the
636  // argument "thisCorner". The "range" argument specifies the width
637  // of the processed patch in each dimension. The corner of the "other"
638  // array where cycling begins is provided by the "otherCorner"
639  // argument. The "arrLen" argument specifies the number of elements
640  // in "thisCorner", "range", and "otherCorner" arrays. It should be
641  // equal to the rank of either of the two ArrayND arrays.
642  //
643  // Note that there is no good way for this method to assume constness
644  // of this or "other" array: this becomes apparent only after the
645  // functor has been specified. Apply const_cast judiciously as needed,
646  // other solutions of this problem are not any better.
647  */
648  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
650  const unsigned* thisCorner,
651  const unsigned* range,
652  const unsigned* otherCorner,
653  unsigned arrLen,
654  Functor binaryFunct);
655 
656  /**
657  // Method similar to "jointSubrangeScan" in which the topology of
658  // both arrays is assumed to be hypertoroidal (circular buffer in
659  // every dimension)
660  */
661  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
663  const unsigned* thisCorner,
664  const unsigned* range,
665  const unsigned* otherCorner,
666  unsigned arrLen,
667  Functor binaryFunct);
668 
669  /**
670  // Method similar to "jointSubrangeScan" in which the topology of
671  // this array is assumed to be flat and the other array hypertoroidal
672  */
673  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
675  const unsigned* thisCorner,
676  const unsigned* range,
677  const unsigned* otherCorner,
678  unsigned arrLen,
679  Functor binaryFunct);
680 
681  /**
682  // Method similar to "jointSubrangeScan" in which the topology of
683  // this array is assumed to be hypertoroidal and the other array flat
684  */
685  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
687  const unsigned* thisCorner,
688  const unsigned* range,
689  const unsigned* otherCorner,
690  unsigned arrLen,
691  Functor binaryFunct);
692 
693  /**
694  // This method runs over a subrange of the array
695  // and calls the argument functor on every point. This
696  // method will not call "clear" or "result" functions of
697  // the argument functor.
698  */
699  template <typename Num2, typename Integer>
701  const BoxND<Integer>& subrange) const;
702 
703  /**
704  // Copy a hyperrectangular subrange of this array potentially
705  // completely overwriting the destination array. The starting
706  // corner in this object where copying begins is provided by
707  // the first two arguments. The subrange size is defined by
708  // the shape of the destination array.
709  */
710  template <typename Num2, unsigned Len2, unsigned Dim2>
711  void exportSubrange(const unsigned* fromCorner, unsigned lenCorner,
712  ArrayND<Num2, Len2, Dim2>* dest) const;
713 
714  /** The inverse operation to "exportSubrange" */
715  template <typename Num2, unsigned Len2, unsigned Dim2>
716  void importSubrange(const unsigned* fromCorner, unsigned lenCorner,
717  const ArrayND<Num2, Len2, Dim2>& from);
718 
719  /**
720  // Check that all elements of this array differ from the
721  // corresponding elements of another array by at most "eps".
722  // Equivalent to maxAbsDifference(r) <= eps (but usually faster).
723  */
724  template <typename Num2, unsigned Len2, unsigned Dim2>
725  bool isClose(const ArrayND<Num2,Len2,Dim2>& r, double eps) const;
726 
727  //@{
728  /** Check compatibility with another shape */
729  bool isCompatible(const ArrayShape& shape) const;
730  bool isCompatible(const unsigned* shape, unsigned dim) const;
731  //@}
732 
733  /**
734  // Check shape compatibility with another array. Equivalent to
735  // but faster than isCompatible(r.shape()).
736  */
737  template <typename Num2, unsigned Len2, unsigned Dim2>
739 
740  /**
741  // Joint cycle over the data of this array and the slice.
742  // The array to which the "slice" argument refers should normally
743  // be created by the slicing constructor using this array as
744  // the argument. The "fixedIndices" argument should be the same
745  // as the "indices" argument in that constructor. This method
746  // is to be used for import/export of slice data and in-place
747  // operations (addition, multiplication, etc).
748  */
749  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
751  const unsigned* fixedIndices,
752  const unsigned* fixedIndexValues,
753  unsigned nFixedIndices,
754  Functor binaryFunct);
755 
756  /**
757  // Joint cycle over a slice this array and some memory buffer.
758  // The length of the buffer must be equal to the length of the
759  // slice, as in "jointSliceScan". This method is to be used
760  // for import/export of slice data and in-place operations
761  // (addition, multiplication, etc) with memory managed not
762  // by ArrayND but in some other manner.
763  */
764  template <typename Num2, class Functor>
765  void jointMemSliceScan(Num2* buffer, unsigned long bufLen,
766  const unsigned* fixedIndices,
767  const unsigned* fixedIndexValues,
768  unsigned nFixedIndices,
769  Functor binaryFunct);
770 
771  /** Figure out the slice shape without actually making the slice */
772  ArrayShape sliceShape(const unsigned* fixedIndices,
773  unsigned nFixedIndices) const;
774 
775  /** Convenience method for exporting a slice of this array */
776  template <typename Num2, unsigned Len2, unsigned Dim2>
778  const unsigned* fixedIndices,
779  const unsigned* fixedIndexValues,
780  unsigned nFixedIndices) const
781  {
782  assert(slice);
783  (const_cast<ArrayND*>(this))->jointSliceScan(
784  *slice, fixedIndices, fixedIndexValues, nFixedIndices,
786  }
787 
788  /**
789  // Convenience method for exporting a slice of this array
790  // into a memory buffer
791  */
792  template <typename Num2>
793  inline void exportMemSlice(Num2* buffer, unsigned long bufLen,
794  const unsigned* fixedIndices,
795  const unsigned* fixedIndexValues,
796  unsigned nFixedIndices) const
797  {
798  (const_cast<ArrayND*>(this))->jointMemSliceScan(
799  buffer, bufLen, fixedIndices, fixedIndexValues,
800  nFixedIndices, scast_assign_right<Numeric,Num2>());
801  }
802 
803  /** Convenience method for importing a slice into this array */
804  template <typename Num2, unsigned Len2, unsigned Dim2>
805  inline void importSlice(const ArrayND<Num2,Len2,Dim2>& slice,
806  const unsigned* fixedIndices,
807  const unsigned* fixedIndexValues,
808  unsigned nFixedIndices)
809  {
810  jointSliceScan(const_cast<ArrayND<Num2,Len2,Dim2>&>(slice),
811  fixedIndices, fixedIndexValues, nFixedIndices,
813  }
814 
815  /**
816  // Convenience method for importing a slice into this array
817  // from a memory buffer
818  */
819  template <typename Num2>
820  inline void importMemSlice(const Num2* buffer, unsigned long bufLen,
821  const unsigned* fixedIndices,
822  const unsigned* fixedIndexValues,
823  unsigned nFixedIndices)
824  {
825  jointMemSliceScan(const_cast<Num2*>(buffer), bufLen,
826  fixedIndices, fixedIndexValues, nFixedIndices,
828  }
829 
830  /**
831  // This method applies the values in the slice to all other
832  // coresponding values in the array. This can be used, for example,
833  // to multiply/divide by some factor which varies across the slice.
834  // The slice values will be used as the right functor argument.
835  */
836  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
838  const unsigned* fixedIndices, unsigned nFixedIndices,
839  Functor binaryFunct);
840 
841  /**
842  // Convenience method which multiplies the array by a scale factor
843  // which varies across the slice
844  */
845  template <typename Num2, unsigned Len2, unsigned Dim2>
847  const unsigned* fixedIndices,
848  unsigned nFixedIndices)
849  {
850  applySlice(const_cast<ArrayND<Num2,Len2,Dim2>&>(slice),
851  fixedIndices, nFixedIndices,
853  return *this;
854  }
855 
856  //@{
857  /**
858  // This method fills a projection. The array to which
859  // "projection" argument points should normally be created by
860  // the slicing constructor using this array as an argument.
861  // "projectedIndices" should be the same as "indices" specified
862  // during the slice creation.
863  */
864  template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
867  const unsigned* projectedIndices,
868  unsigned nProjectedIndices) const;
869 
870  template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
871  void project(ArrayND<Num2,Len2,Dim2>* projection,
872  AbsVisitor<Numeric,Num3>& projector,
873  const unsigned* projectedIndices,
874  unsigned nProjectedIndices) const;
875  //@}
876 
877  //@{
878  /**
879  // Similar method to "project", but projections are added to
880  // (or subtracted from) the existing projection data instead of
881  // replacing them
882  */
883  template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
886  const unsigned* projectedIndices,
887  unsigned nProjectedIndices) const;
888 
889  template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
890  void subtractFromProjection(ArrayND<Num2,Len2,Dim2>* projection,
892  const unsigned* projectedIndices,
893  unsigned nProjectedIndices) const;
894 
895  template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
896  void addToProjection(ArrayND<Num2,Len2,Dim2>* projection,
897  AbsVisitor<Numeric,Num3>& projector,
898  const unsigned* projectedIndices,
899  unsigned nProjectedIndices) const;
900 
901  template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
902  void subtractFromProjection(ArrayND<Num2,Len2,Dim2>* projection,
903  AbsVisitor<Numeric,Num3>& projector,
904  const unsigned* projectedIndices,
905  unsigned nProjectedIndices) const;
906  //@}
907 
908  /**
909  // Rotation. Place the result into another array. The elements
910  // with indices 0 in the current array will become elements with
911  // indices "shifts" in the rotated array.
912  */
913  template <typename Num2, unsigned Len2, unsigned Dim2>
914  void rotate(const unsigned* shifts, unsigned lenShifts,
915  ArrayND<Num2, Len2, Dim2>* rotated) const;
916 
917  /**
918  // Mirror this array into another array w.r.t. the dimensions
919  // provided by the arguments. The other array must have the
920  // same spans as this one.
921  */
922  template <typename Num2, unsigned Len2, unsigned Dim2>
923  void mirror(const unsigned* mirrorDims, unsigned mirrorLen,
924  ArrayND<Num2, Len2, Dim2>* out) const;
925 
926  /**
927  // Fill another array with all possible mirror images
928  // of this one. This other array must have twice the span
929  // in each dimension.
930  */
931  template <typename Num2, unsigned Len2, unsigned Dim2>
933 
934  //@{
935  /**
936  // Fortran-style subscripting without bounds checking (of course,
937  // with indices starting at 0).
938  */
939  Numeric& operator()();
940  const Numeric& operator()() const;
941 
942  Numeric& operator()(unsigned i0);
943  const Numeric& operator()(unsigned i0) const;
944 
945  Numeric& operator()(unsigned i0, unsigned i1);
946  const Numeric& operator()(unsigned i0, unsigned i1) const;
947 
948  Numeric& operator()(unsigned i0, unsigned i1, unsigned i2);
949  const Numeric& operator()(unsigned i0, unsigned i1, unsigned i2) const;
950 
951  Numeric& operator()(unsigned i0, unsigned i1,
952  unsigned i2, unsigned i3);
953  const Numeric& operator()(unsigned i0, unsigned i1,
954  unsigned i2, unsigned i3) const;
955 
956  Numeric& operator()(unsigned i0, unsigned i1,
957  unsigned i2, unsigned i3, unsigned i4);
958  const Numeric& operator()(unsigned i0, unsigned i1,
959  unsigned i2, unsigned i3, unsigned i4) const;
960 
961  Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
962  unsigned i3, unsigned i4, unsigned i5);
963  const Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
964  unsigned i3, unsigned i4, unsigned i5) const;
965 
966  Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
967  unsigned i3, unsigned i4, unsigned i5,
968  unsigned i6);
969  const Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
970  unsigned i3, unsigned i4, unsigned i5,
971  unsigned i6) const;
972 
973  Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
974  unsigned i3, unsigned i4, unsigned i5,
975  unsigned i6, unsigned i7);
976  const Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
977  unsigned i3, unsigned i4, unsigned i5,
978  unsigned i6, unsigned i7) const;
979 
980  Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
981  unsigned i3, unsigned i4, unsigned i5,
982  unsigned i6, unsigned i7, unsigned i8);
983  const Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
984  unsigned i3, unsigned i4, unsigned i5,
985  unsigned i6, unsigned i7, unsigned i8) const;
986 
987  Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
988  unsigned i3, unsigned i4, unsigned i5,
989  unsigned i6, unsigned i7, unsigned i8,
990  unsigned i9);
991  const Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
992  unsigned i3, unsigned i4, unsigned i5,
993  unsigned i6, unsigned i7, unsigned i8,
994  unsigned i9) const;
995  //@}
996 
997  //@{
998  /**
999  // Fortran-style subscripting with bounds checking (of course,
1000  // with indices starting at 0).
1001  */
1002  Numeric& at();
1003  const Numeric& at() const;
1004 
1005  Numeric& at(unsigned i0);
1006  const Numeric& at(unsigned i0) const;
1007 
1008  Numeric& at(unsigned i0, unsigned i1);
1009  const Numeric& at(unsigned i0, unsigned i1) const;
1010 
1011  Numeric& at(unsigned i0, unsigned i1, unsigned i2);
1012  const Numeric& at(unsigned i0, unsigned i1, unsigned i2) const;
1013 
1014  Numeric& at(unsigned i0, unsigned i1,
1015  unsigned i2, unsigned i3);
1016  const Numeric& at(unsigned i0, unsigned i1,
1017  unsigned i2, unsigned i3) const;
1018 
1019  Numeric& at(unsigned i0, unsigned i1,
1020  unsigned i2, unsigned i3, unsigned i4);
1021  const Numeric& at(unsigned i0, unsigned i1,
1022  unsigned i2, unsigned i3, unsigned i4) const;
1023 
1024  Numeric& at(unsigned i0, unsigned i1, unsigned i2,
1025  unsigned i3, unsigned i4, unsigned i5);
1026  const Numeric& at(unsigned i0, unsigned i1, unsigned i2,
1027  unsigned i3, unsigned i4, unsigned i5) const;
1028 
1029  Numeric& at(unsigned i0, unsigned i1, unsigned i2,
1030  unsigned i3, unsigned i4, unsigned i5,
1031  unsigned i6);
1032  const Numeric& at(unsigned i0, unsigned i1, unsigned i2,
1033  unsigned i3, unsigned i4, unsigned i5,
1034  unsigned i6) const;
1035 
1036  Numeric& at(unsigned i0, unsigned i1, unsigned i2,
1037  unsigned i3, unsigned i4, unsigned i5,
1038  unsigned i6, unsigned i7);
1039  const Numeric& at(unsigned i0, unsigned i1, unsigned i2,
1040  unsigned i3, unsigned i4, unsigned i5,
1041  unsigned i6, unsigned i7) const;
1042 
1043  Numeric& at(unsigned i0, unsigned i1, unsigned i2,
1044  unsigned i3, unsigned i4, unsigned i5,
1045  unsigned i6, unsigned i7, unsigned i8);
1046  const Numeric& at(unsigned i0, unsigned i1, unsigned i2,
1047  unsigned i3, unsigned i4, unsigned i5,
1048  unsigned i6, unsigned i7, unsigned i8) const;
1049 
1050  Numeric& at(unsigned i0, unsigned i1, unsigned i2,
1051  unsigned i3, unsigned i4, unsigned i5,
1052  unsigned i6, unsigned i7, unsigned i8,
1053  unsigned i9);
1054  const Numeric& at(unsigned i0, unsigned i1, unsigned i2,
1055  unsigned i3, unsigned i4, unsigned i5,
1056  unsigned i6, unsigned i7, unsigned i8,
1057  unsigned i9) const;
1058  //@}
1059 
1060  //@{
1061  /**
1062  // Subscripting by continuous coordinate.
1063  // Works similar to the "closest" method.
1064  */
1065  Numeric& cl();
1066  const Numeric& cl() const;
1067 
1068  Numeric& cl(double x0);
1069  const Numeric& cl(double x0) const;
1070 
1071  Numeric& cl(double x0, double x1);
1072  const Numeric& cl(double x0, double x1) const;
1073 
1074  Numeric& cl(double x0, double x1, double x2);
1075  const Numeric& cl(double x0, double x1, double x2) const;
1076 
1077  Numeric& cl(double x0, double x1,
1078  double x2, double x3);
1079  const Numeric& cl(double x0, double x1,
1080  double x2, double x3) const;
1081 
1082  Numeric& cl(double x0, double x1,
1083  double x2, double x3, double x4);
1084  const Numeric& cl(double x0, double x1,
1085  double x2, double x3, double x4) const;
1086 
1087  Numeric& cl(double x0, double x1, double x2,
1088  double x3, double x4, double x5);
1089  const Numeric& cl(double x0, double x1, double x2,
1090  double x3, double x4, double x5) const;
1091 
1092  Numeric& cl(double x0, double x1, double x2,
1093  double x3, double x4, double x5,
1094  double x6);
1095  const Numeric& cl(double x0, double x1, double x2,
1096  double x3, double x4, double x5,
1097  double x6) const;
1098 
1099  Numeric& cl(double x0, double x1, double x2,
1100  double x3, double x4, double x5,
1101  double x6, double x7);
1102  const Numeric& cl(double x0, double x1, double x2,
1103  double x3, double x4, double x5,
1104  double x6, double x7) const;
1105 
1106  Numeric& cl(double x0, double x1, double x2,
1107  double x3, double x4, double x5,
1108  double x6, double x7, double x8);
1109  const Numeric& cl(double x0, double x1, double x2,
1110  double x3, double x4, double x5,
1111  double x6, double x7, double x8) const;
1112 
1113  Numeric& cl(double x0, double x1, double x2,
1114  double x3, double x4, double x5,
1115  double x6, double x7, double x8,
1116  double x9);
1117  const Numeric& cl(double x0, double x1, double x2,
1118  double x3, double x4, double x5,
1119  double x6, double x7, double x8,
1120  double x9) const;
1121  //@}
1122 
1123  //@{
1124  /** Method related to "geners" I/O */
1125  inline gs::ClassId classId() const {return gs::ClassId(*this);}
1126  bool write(std::ostream& of) const;
1127  //@}
1128 
1129  static const char* classname();
1130  static inline unsigned version() {return 1;}
1131  static void restore(const gs::ClassId& id, std::istream& in,
1132  ArrayND* array);
1133  private:
1134  Numeric localData_[StackLen];
1135  Numeric* data_;
1136 
1137  unsigned long localStrides_[StackDim];
1138  unsigned long *strides_;
1139 
1140  unsigned localShape_[StackDim];
1141  unsigned *shape_;
1142 
1143  unsigned long len_;
1144  unsigned dim_;
1145 
1146  bool shapeIsKnown_;
1147  bool dataIsExternal_;
1148 
1149  // Basic initialization from unsigned* shape and dimensionality
1150  void buildFromShapePtr(const unsigned*, unsigned);
1151 
1152  // Basic initialization from unsigned* shape, dimensionality,
1153  // and external data buffer which we will manage but will not own
1154  void buildExtFromShapePtr(const unsigned*, unsigned, Numeric*);
1155 
1156  // Build strides_ array out of the shape_ array
1157  void buildStrides();
1158 
1159  // Recursive implementation of nested loops for "linearFill"
1160  void linearFillLoop(unsigned level, double s0,
1161  unsigned long idx, double shift,
1162  const double* coeffs);
1163 
1164  // Recursive implementation of nested loops for "functorFill"
1165  template <class Functor>
1166  void functorFillLoop(unsigned level, unsigned long idx,
1167  Functor f, unsigned* farg);
1168 
1169  // Recursive implementation of nested loops for "interpolate3"
1170  Numeric interpolateLoop(unsigned level, const double* x,
1171  const Numeric* base) const;
1172 
1173  // Recursive implementation of nested loops for the outer product
1174  template <typename Num1, unsigned Len1, unsigned Dim1,
1175  typename Num2, unsigned Len2, unsigned Dim2>
1176  void outerProductLoop(unsigned level, unsigned long idx0,
1177  unsigned long idx1, unsigned long idx2,
1178  const ArrayND<Num1, Len1, Dim1>& a1,
1179  const ArrayND<Num2, Len2, Dim2>& a2);
1180 
1181  // Recursive implementation of nested loops for contraction
1182  void contractLoop(unsigned thisLevel, unsigned resLevel,
1183  unsigned pos1, unsigned pos2,
1184  unsigned long idxThis, unsigned long idxRes,
1185  ArrayND& result) const;
1186 
1187  // Recursive implementation of nested loops for transposition
1188  void transposeLoop(unsigned level, unsigned pos1, unsigned pos2,
1189  unsigned long idxThis, unsigned long idxRes,
1190  ArrayND& result) const;
1191 
1192  // Recursive implementation of nested loops for the dot product
1193  template <typename Num2, unsigned Len2, unsigned Dim2>
1194  void dotProductLoop(unsigned level, unsigned long idx0,
1195  unsigned long idx1, unsigned long idx2,
1196  const ArrayND<Num2, Len2, Dim2>& r,
1197  ArrayND& result) const;
1198 
1199  // Recursive implementation of nested loops for marginalization
1200  template <typename Num2, unsigned Len2, unsigned Dim2>
1201  Numeric marginalizeInnerLoop(unsigned long idx,
1202  unsigned levelPr, unsigned long idxPr,
1203  const ArrayND<Num2,Len2,Dim2>& prior,
1204  const unsigned* indexMap) const;
1205  template <typename Num2, unsigned Len2, unsigned Dim2>
1206  void marginalizeLoop(unsigned level, unsigned long idx,
1207  unsigned levelRes, unsigned long idxRes,
1208  const ArrayND<Num2,Len2,Dim2>& prior,
1209  const unsigned* indexMap, ArrayND& res) const;
1210 
1211  // Recursive implementation of nested loops for range copy
1212  // with functor modification of elements
1213  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
1214  void copyRangeLoopFunct(unsigned level, unsigned long idx0,
1215  unsigned long idx1,
1216  const ArrayND<Num2, Len2, Dim2>& r,
1217  const ArrayRange& range, Functor f);
1218 
1219  // Loop over subrange in such a way that the functor is called
1220  // only if indices on both sides are valid. The topology of both
1221  // arrays is that of the hyperplane (flat).
1222  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
1223  void commonSubrangeLoop(unsigned level, unsigned long idx0,
1224  unsigned long idx1,
1225  const unsigned* thisCorner,
1226  const unsigned* range,
1227  const unsigned* otherCorner,
1228  ArrayND<Num2, Len2, Dim2>& other,
1229  Functor binaryFunct);
1230 
1231  // Similar loop with the topology of the hypertorus for both
1232  // arrays (all indices of both arrays are wrapped around)
1233  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
1234  void dualCircularLoop(unsigned level, unsigned long idx0,
1235  unsigned long idx1,
1236  const unsigned* thisCorner,
1237  const unsigned* range,
1238  const unsigned* otherCorner,
1239  ArrayND<Num2, Len2, Dim2>& other,
1240  Functor binaryFunct);
1241 
1242  // Similar loop in which the topology of this array is assumed
1243  // to be flat and the topology of the destination array is that
1244  // of the hypertorus. Due to the asymmetry of the topologies,
1245  // "const" function is not provided (use const_cast as appropriate).
1246  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
1247  void flatCircularLoop(unsigned level, unsigned long idx0,
1248  unsigned long idx1,
1249  const unsigned* thisCorner,
1250  const unsigned* range,
1251  const unsigned* otherCorner,
1252  ArrayND<Num2, Len2, Dim2>& other,
1253  Functor binaryFunct);
1254 
1255  // Similar loop in which the topology of this array is assumed
1256  // to be hypertoroidal and the topology of the destination array
1257  // is flat.
1258  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
1259  void circularFlatLoop(unsigned level, unsigned long idx0,
1260  unsigned long idx1,
1261  const unsigned* thisCorner,
1262  const unsigned* range,
1263  const unsigned* otherCorner,
1264  ArrayND<Num2, Len2, Dim2>& other,
1265  Functor binaryFunct);
1266 
1267  // Slice compatibility verification
1268  template <typename Num2, unsigned Len2, unsigned Dim2>
1269  unsigned long verifySliceCompatibility(
1270  const ArrayND<Num2,Len2,Dim2>& slice,
1271  const unsigned* fixedIndices,
1272  const unsigned* fixedIndexValues,
1273  unsigned nFixedIndices) const;
1274 
1275  // Buffer compatibility verification with a slice
1276  unsigned long verifyBufferSliceCompatibility(
1277  unsigned long bufLen,
1278  const unsigned* fixedIndices,
1279  const unsigned* fixedIndexValues,
1280  unsigned nFixedIndices,
1281  unsigned long* sliceStrides) const;
1282 
1283  // Recursive implementation of nested loops for slice operations
1284  template <typename Num2, class Functor>
1285  void jointSliceLoop(unsigned level, unsigned long idx0,
1286  unsigned level1, unsigned long idx1,
1287  Num2* sliceData, const unsigned long* sliceStrides,
1288  const unsigned* fixedIndices,
1289  const unsigned* fixedIndexValues,
1290  unsigned nFixedIndices, Functor binaryFunctor);
1291 
1292  // Recursive implementation of nested loops for "applySlice"
1293  template <typename Num2, class Functor>
1294  void scaleBySliceInnerLoop(unsigned level, unsigned long idx0,
1295  Num2& scale,
1296  const unsigned* projectedIndices,
1297  unsigned nProjectedIndices,
1298  Functor binaryFunct);
1299 
1300  template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
1301  void scaleBySliceLoop(unsigned level, unsigned long idx0,
1302  unsigned level1, unsigned long idx1,
1303  ArrayND<Num2,Len2,Dim2>& slice,
1304  const unsigned* fixedIndices,
1305  unsigned nFixedIndices,
1306  Functor binaryFunct);
1307 
1308  // Recursive implementation of nested loops for projections
1309  template <typename Num2>
1310  void projectInnerLoop(unsigned level, unsigned long idx0,
1311  unsigned* currentIndex,
1312  AbsArrayProjector<Numeric,Num2>& projector,
1313  const unsigned* projectedIndices,
1314  unsigned nProjectedIndices) const;
1315 
1316  template <typename Num2, unsigned Len2, unsigned Dim2,
1317  typename Num3, class Op>
1318  void projectLoop(unsigned level, unsigned long idx0,
1319  unsigned level1, unsigned long idx1,
1320  unsigned* currentIndex,
1321  ArrayND<Num2,Len2,Dim2>* projection,
1322  AbsArrayProjector<Numeric,Num3>& projector,
1323  const unsigned* projectedIndices,
1324  unsigned nProjectedIndices, Op fcn) const;
1325 
1326  // Note that "projectLoop2" is almost identical to "projectLoop"
1327  // while "projectInnerLoop2" is almost identical to "projectInnerLoop".
1328  // It would make a lot of sense to combine these functions into
1329  // the same code and then partially specialize the little piece
1330  // where the "AbsVisitor" or "AbsArrayProjector" is actually called.
1331  // Unfortunately, "AbsVisitor" and "AbsArrayProjector" are
1332  // templates themselves, and it is not possible in C++ to partially
1333  // specialize a function template (that is, even if we can specialize
1334  // on "AbsVisitor" vs. "AbsArrayProjector", there is no way to
1335  // specialize on their parameter types).
1336  template <typename Num2, unsigned Len2, unsigned Dim2,
1337  typename Num3, class Op>
1338  void projectLoop2(unsigned level, unsigned long idx0,
1339  unsigned level1, unsigned long idx1,
1340  ArrayND<Num2,Len2,Dim2>* projection,
1341  AbsVisitor<Numeric,Num3>& projector,
1342  const unsigned* projectedIndices,
1343  unsigned nProjectedIndices, Op fcn) const;
1344 
1345  template <typename Num2>
1346  void projectInnerLoop2(unsigned level, unsigned long idx0,
1347  AbsVisitor<Numeric,Num2>& projector,
1348  const unsigned* projectedIndices,
1349  unsigned nProjectedIndices) const;
1350 
1351  template <typename Num2, typename Integer>
1352  void processSubrangeLoop(unsigned level, unsigned long idx0,
1353  unsigned* currentIndex,
1354  AbsArrayProjector<Numeric,Num2>& f,
1355  const BoxND<Integer>& subrange) const;
1356 
1357  // Sum of all points with the given index and below
1358  template <typename Accumulator>
1359  Accumulator sumBelowLoop(unsigned level, unsigned long idx0,
1360  const unsigned* limit) const;
1361 
1362  // Loop for "convertToLastDimCdf"
1363  template <typename Accumulator>
1364  void convertToLastDimCdfLoop(ArrayND* sumSlice, unsigned level,
1365  unsigned long idx0,
1366  unsigned long idxSlice,
1367  bool useTrapezoids);
1368 
1369  // Convert a coordinate into index.
1370  // No checking whether "idim" is within limits.
1371  unsigned coordToIndex(double coord, unsigned idim) const;
1372 
1373  // Verify that projection array is compatible with this one
1374  template <typename Num2, unsigned Len2, unsigned Dim2>
1375  void verifyProjectionCompatibility(
1376  const ArrayND<Num2,Len2,Dim2>& projection,
1377  const unsigned* projectedIndices,
1378  unsigned nProjectedIndices) const;
1379 
1380  template <typename Num2, unsigned Len2, unsigned Dim2>
1381  void coarseSum2(unsigned idim, ArrayND<Num2,Len2,Dim2>* result) const;
1382 
1383  template <typename Num2, unsigned Len2, unsigned Dim2>
1384  void coarseSum3(unsigned idim, ArrayND<Num2,Len2,Dim2>* result) const;
1385 
1386  template <typename Num2, unsigned Len2, unsigned Dim2>
1387  void coarseSumN(unsigned idim, unsigned n,
1388  ArrayND<Num2,Len2,Dim2>* result) const;
1389 
1390  template <typename Num2>
1391  friend ArrayND<Num2> externalMemArrayND(Num2* data,
1392  const unsigned* shape, unsigned dim);
1393  template <typename Num2>
1394  friend ArrayND<Num2> externalMemArrayND(Num2* data, const ArrayShape& shape);
1395 
1396  template <typename Num2>
1397  friend ArrayND<Num2> externalMemArrayND(Num2* data, unsigned n0);
1398 
1399  template <typename Num2>
1400  friend ArrayND<Num2> externalMemArrayND(Num2* data, unsigned n0, unsigned n1);
1401 
1402  template <typename Num2>
1403  friend ArrayND<Num2> externalMemArrayND(Num2* data, unsigned n0, unsigned n1,
1404  unsigned n2);
1405  template <typename Num2>
1406  friend ArrayND<Num2> externalMemArrayND(Num2* data, unsigned n0, unsigned n1,
1407  unsigned n2, unsigned n3);
1408  template <typename Num2>
1409  friend ArrayND<Num2> externalMemArrayND(Num2* data, unsigned n0, unsigned n1,
1410  unsigned n2, unsigned n3, unsigned n4);
1411  template <typename Num2>
1412  friend ArrayND<Num2> externalMemArrayND(Num2* data, unsigned n0, unsigned n1,
1413  unsigned n2, unsigned n3, unsigned n4,
1414  unsigned n5);
1415  template <typename Num2>
1416  friend ArrayND<Num2> externalMemArrayND(Num2* data, unsigned n0, unsigned n1,
1417  unsigned n2, unsigned n3, unsigned n4,
1418  unsigned n5, unsigned n6);
1419  template <typename Num2>
1420  friend ArrayND<Num2> externalMemArrayND(Num2* data, unsigned n0, unsigned n1,
1421  unsigned n2, unsigned n3, unsigned n4,
1422  unsigned n5, unsigned n6, unsigned n7);
1423  template <typename Num2>
1424  friend ArrayND<Num2> externalMemArrayND(Num2* data, unsigned n0, unsigned n1,
1425  unsigned n2, unsigned n3, unsigned n4,
1426  unsigned n5, unsigned n6, unsigned n7,
1427  unsigned n8);
1428  template <typename Num2>
1429  friend ArrayND<Num2> externalMemArrayND(Num2* data, unsigned n0, unsigned n1,
1430  unsigned n2, unsigned n3, unsigned n4,
1431  unsigned n5, unsigned n6, unsigned n7,
1432  unsigned n8, unsigned n9);
1433  template <typename Num2>
1434  friend CPP11_auto_ptr<ArrayND<Num2> > allocExternalMemArrayND(
1435  Num2* data, const unsigned* shape, unsigned dim);
1436 
1437  template <typename Num2>
1438  friend CPP11_auto_ptr<ArrayND<Num2> > allocExternalMemArrayND(
1439  Num2* data, const ArrayShape& shape);
1440 
1441  template <typename Num3, unsigned Len3, unsigned Dim3,
1442  typename Num2, unsigned Len2, unsigned Dim2>
1443 #ifdef SWIGBUG
1444  friend
1445 #endif
1449 #ifndef SWIGBUG
1450  friend
1451 #endif
1452  ::operator+(const npstat::ArrayND<Num3,Len3,Dim3>& l,
1454 
1455  template <typename Num3, unsigned Len3, unsigned Dim3,
1456  typename Num2, unsigned Len2, unsigned Dim2>
1457 #ifdef SWIGBUG
1458  friend
1459 #endif
1463 #ifndef SWIGBUG
1464  friend
1465 #endif
1466  ::operator-(const npstat::ArrayND<Num3,Len3,Dim3>& l,
1468 
1469  template <typename Num3, unsigned Len3, unsigned Dim3,
1470  typename Num2, unsigned Len2, unsigned Dim2>
1471 #ifdef SWIGBUG
1472  friend
1473 #endif
1477 #ifndef SWIGBUG
1478  friend
1479 #endif
1480  ::operator*(const npstat::ArrayND<Num3,Len3,Dim3>& l,
1482 
1483  template <typename Num3, unsigned Len3, unsigned Dim3,
1484  typename Num2, unsigned Len2, unsigned Dim2>
1485 #ifdef SWIGBUG
1486  friend
1487 #endif
1491 #ifndef SWIGBUG
1492  friend
1493 #endif
1494  ::operator/(const npstat::ArrayND<Num3,Len3,Dim3>& l,
1496 
1497 #ifdef SWIG
1498  // Additional ArrayND methods necessary to construct a reasonable
1499  // python interface. SWIG has a major problem we have to address
1500  // here: it converts all access by reference into access by pointer.
1501  // However, in python we can't use pointers explicitly. Of course,
1502  // additional methods like "dereference" or "assign" can be written
1503  // for pointers, but the interface becomes ugly. Therefore, methods
1504  // below access array elements by value. Another problem we have to
1505  // consider is that SWIG support for wrapping template methods in
1506  // template classes is weak.
1507  //
1508  // Note that various "get" methods introduced below are renamed by
1509  // SWIG so that in python they end up named just like the original
1510  // C++ methods which return references. The "set" methods are
1511  // unchanged.
1512  //
1513  // Do not use these methods in pure C++ programs.
1514  //
1515  public:
1516  inline void setValue(const unsigned* indexS, unsigned indexLenS,
1517  Numeric v)
1518  {valueAt(indexS, indexLenS) = v;}
1519  inline Numeric getValue(const unsigned* indexS, unsigned indexLenS) const
1520  {return valueAt(indexS, indexLenS);}
1521 
1522  inline void setLinearValue(unsigned long index, Numeric v)
1523  {linearValueAt(index) = v;}
1524  inline Numeric getLinearValue(unsigned long index) const
1525  {return linearValueAt(index);}
1526 
1527  inline void setClosest(const double* x, unsigned xDim, Numeric v)
1528  {closest(x, xDim) = v;}
1529  const Numeric getClosest(const double* x, unsigned xDim) const
1530  {return closest(x, xDim);}
1531 
1532  inline void set(Numeric v)
1533  {at() = v;}
1534  inline Numeric get() const
1535  {return at();}
1536 
1537  inline void set(unsigned i0, Numeric v)
1538  {at(i0) = v;}
1539  inline Numeric get(unsigned i0) const
1540  {return at(i0);}
1541 
1542  inline void set(unsigned i0, unsigned i1, Numeric v)
1543  {at(i0,i1) = v;}
1544  inline Numeric get(unsigned i0, unsigned i1) const
1545  {return at(i0,i1);}
1546 
1547  inline void set(unsigned i0, unsigned i1, unsigned i2, Numeric v)
1548  {at(i0,i1,i2) = v;}
1549  inline Numeric get(unsigned i0, unsigned i1, unsigned i2) const
1550  {return at(i0,i1,i2);}
1551 
1552  inline void set(unsigned i0, unsigned i1,
1553  unsigned i2, unsigned i3, Numeric v)
1554  {at(i0,i1,i2,i3) = v;}
1555  inline Numeric get(unsigned i0, unsigned i1,
1556  unsigned i2, unsigned i3) const
1557  {return at(i0,i1,i2,i3);}
1558 
1559  inline void set(unsigned i0, unsigned i1,
1560  unsigned i2, unsigned i3, unsigned i4, Numeric v)
1561  {at(i0,i1,i2,i3,i4) = v;}
1562  inline Numeric get(unsigned i0, unsigned i1,
1563  unsigned i2, unsigned i3, unsigned i4) const
1564  {return at(i0,i1,i2,i3,i4);}
1565 
1566  inline void set(unsigned i0, unsigned i1, unsigned i2,
1567  unsigned i3, unsigned i4, unsigned i5, Numeric v)
1568  {at(i0,i1,i2,i3,i4,i5) = v;}
1569  inline Numeric get(unsigned i0, unsigned i1, unsigned i2,
1570  unsigned i3, unsigned i4, unsigned i5) const
1571  {return at(i0,i1,i2,i3,i4,i5);}
1572 
1573  inline void set(unsigned i0, unsigned i1, unsigned i2,
1574  unsigned i3, unsigned i4, unsigned i5,
1575  unsigned i6, Numeric v)
1576  {at(i0,i1,i2,i3,i4,i5,i6) = v;}
1577  inline Numeric get(unsigned i0, unsigned i1, unsigned i2,
1578  unsigned i3, unsigned i4, unsigned i5,
1579  unsigned i6) const
1580  {return at(i0,i1,i2,i3,i4,i5,i6);}
1581 
1582  inline void set(unsigned i0, unsigned i1, unsigned i2,
1583  unsigned i3, unsigned i4, unsigned i5,
1584  unsigned i6, unsigned i7, Numeric v)
1585  {at(i0,i1,i2,i3,i4,i5,i6,i7) = v;}
1586  inline Numeric get(unsigned i0, unsigned i1, unsigned i2,
1587  unsigned i3, unsigned i4, unsigned i5,
1588  unsigned i6, unsigned i7) const
1589  {return at(i0,i1,i2,i3,i4,i5,i6,i7);}
1590 
1591  inline void set(unsigned i0, unsigned i1, unsigned i2,
1592  unsigned i3, unsigned i4, unsigned i5,
1593  unsigned i6, unsigned i7, unsigned i8, Numeric v)
1594  {at(i0,i1,i2,i3,i4,i5,i6,i7,i8) = v;}
1595  inline Numeric get(unsigned i0, unsigned i1, unsigned i2,
1596  unsigned i3, unsigned i4, unsigned i5,
1597  unsigned i6, unsigned i7, unsigned i8) const
1598  {return at(i0,i1,i2,i3,i4,i5,i6,i7,i8);}
1599 
1600  inline void set(unsigned i0, unsigned i1, unsigned i2,
1601  unsigned i3, unsigned i4, unsigned i5,
1602  unsigned i6, unsigned i7, unsigned i8,
1603  unsigned i9, Numeric v)
1604  {at(i0,i1,i2,i3,i4,i5,i6,i7,i8,i9) = v;}
1605  inline Numeric get(unsigned i0, unsigned i1, unsigned i2,
1606  unsigned i3, unsigned i4, unsigned i5,
1607  unsigned i6, unsigned i7, unsigned i8,
1608  unsigned i9) const
1609  {return at(i0,i1,i2,i3,i4,i5,i6,i7,i8,i9);}
1610 
1611  inline void setCl(Numeric v)
1612  {cl() = v;}
1613  inline Numeric getCl() const
1614  {return cl();}
1615 
1616  inline void setCl(double x0, Numeric v)
1617  {cl(x0) = v;}
1618  inline Numeric getCl(double x0) const
1619  {return cl(x0);}
1620 
1621  inline void setCl(double x0, double x1, Numeric v)
1622  {cl(x0, x1) = v;}
1623  inline Numeric getCl(double x0, double x1) const
1624  {return cl(x0, x1);}
1625 
1626  inline void setCl(double x0, double x1, double x2, Numeric v)
1627  {cl(x0, x1, x2) = v;}
1628  inline Numeric getCl(double x0, double x1, double x2) const
1629  {return cl(x0, x1, x2);}
1630 
1631  inline void setCl(double x0, double x1,
1632  double x2, double x3, Numeric v)
1633  {cl(x0, x1, x2, x3) = v;}
1634  inline Numeric getCl(double x0, double x1,
1635  double x2, double x3) const
1636  {return cl(x0, x1, x2, x3);}
1637 
1638  inline void setCl(double x0, double x1,
1639  double x2, double x3, double x4, Numeric v)
1640  {cl(x0, x1, x2, x3, x4) = v;}
1641  inline Numeric getCl(double x0, double x1,
1642  double x2, double x3, double x4) const
1643  {return cl(x0, x1, x2, x3, x4);}
1644 
1645  inline void setCl(double x0, double x1, double x2,
1646  double x3, double x4, double x5, Numeric v)
1647  {cl(x0, x1, x2, x3, x4, x5) = v;}
1648  inline Numeric getCl(double x0, double x1, double x2,
1649  double x3, double x4, double x5) const
1650  {return cl(x0, x1, x2, x3, x4, x5);}
1651 
1652  inline void setCl(double x0, double x1, double x2,
1653  double x3, double x4, double x5,
1654  double x6, Numeric v)
1655  {cl(x0, x1, x2, x3, x4, x5, x6) = v;}
1656  inline Numeric getCl(double x0, double x1, double x2,
1657  double x3, double x4, double x5,
1658  double x6) const
1659  {return cl(x0, x1, x2, x3, x4, x5, x6);}
1660 
1661  inline void setCl(double x0, double x1, double x2,
1662  double x3, double x4, double x5,
1663  double x6, double x7, Numeric v)
1664  {cl(x0, x1, x2, x3, x4, x5, x6, x7) = v;}
1665  inline Numeric getCl(double x0, double x1, double x2,
1666  double x3, double x4, double x5,
1667  double x6, double x7) const
1668  {return cl(x0, x1, x2, x3, x4, x5, x6, x7);}
1669 
1670  inline void setCl(double x0, double x1, double x2,
1671  double x3, double x4, double x5,
1672  double x6, double x7, double x8, Numeric v)
1673  {cl(x0, x1, x2, x3, x4, x5, x6, x7, x8) = v;}
1674  inline Numeric getCl(double x0, double x1, double x2,
1675  double x3, double x4, double x5,
1676  double x6, double x7, double x8) const
1677  {return cl(x0, x1, x2, x3, x4, x5, x6, x7, x8);}
1678 
1679  inline void setCl(double x0, double x1, double x2,
1680  double x3, double x4, double x5,
1681  double x6, double x7, double x8,
1682  double x9, Numeric v)
1683  {cl(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) = v;}
1684  inline Numeric getCl(double x0, double x1, double x2,
1685  double x3, double x4, double x5,
1686  double x6, double x7, double x8,
1687  double x9) const
1688  {return cl(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9);}
1689 
1690  inline void setData2(const Numeric* data, unsigned long dataLength)
1691  {setData(data, dataLength);}
1692 
1693  inline double maxAbsDifference2(const ArrayND& r) const
1694  {return maxAbsDifference(r);}
1695 
1696  inline bool isEqual2(const ArrayND& r) const
1697  {return *this == r;}
1698 
1699  inline bool notEqual2(const ArrayND& r) const
1700  {return !(*this == r);}
1701 
1702  inline ArrayND plus2(const ArrayND& r) const
1703  {return *this + r;}
1704 
1705  inline ArrayND minus2(const ArrayND& r) const
1706  {return *this - r;}
1707 
1708  inline ArrayND arrmul2(const ArrayND& r) const
1709  {return *this * r;}
1710 
1711  inline ArrayND arrdiv2(const ArrayND& r) const
1712  {return *this / r;}
1713 
1714  inline ArrayND mul2(const double r) const
1715  {return *this * static_cast<proper_double>(r);}
1716 
1717  inline ArrayND rmul2(const double r) const
1718  {return *this * static_cast<proper_double>(r);}
1719 
1720  inline ArrayND div2(const double r) const
1721  {return *this / static_cast<proper_double>(r);}
1722 
1723  inline ArrayND& iarrmul2(const ArrayND& r)
1724  {*this *= r; return *this;}
1725 
1726  inline ArrayND& iarrdiv2(const ArrayND& r)
1727  {*this /= r; return *this;}
1728 
1729  inline ArrayND& iadd2(const ArrayND& r)
1730  {*this += r; return *this;}
1731 
1732  inline ArrayND& isub2(const ArrayND& r)
1733  {*this -= r; return *this;}
1734 
1735  inline ArrayND& imul2(const double r)
1736  {*this *= static_cast<proper_double>(r); return *this;}
1737 
1738  inline ArrayND& idiv2(const double r)
1739  {*this /= static_cast<proper_double>(r); return *this;}
1740 
1741  inline ArrayND& addmul2(const ArrayND& r, const double c)
1742  {return addmul(r, static_cast<proper_double>(c));}
1743 
1744  inline ArrayND outer2(const ArrayND& r) const
1745  {return outer(r);}
1746 
1747  inline ArrayND dot2(const ArrayND& r) const
1748  {return dot(r);}
1749 
1750  inline ArrayND marginalize2(
1751  const ArrayND<proper_double>& r,
1752  const unsigned* indexMapX, const unsigned mapLenX) const
1753  {return marginalize(r, indexMapX, mapLenX);}
1754 
1755  inline Numeric sum2() const
1756  {return static_cast<Numeric>((*this).template sum<
1757  typename PreciseType<Numeric>::type>());}
1758 
1759  inline double sumsq2() const
1760  {return (*this).template sumsq<long double>();}
1761 
1762  inline ArrayND derivative2(double scale=1.0) const
1763  {return (*this).template derivative<
1764  typename PreciseType<Numeric>::type>(scale);}
1765 
1766  inline ArrayND cdfArray2(double scale=1.0) const
1767  {return (*this).template cdfArray<
1768  typename PreciseType<Numeric>::type>(scale);}
1769 
1770  inline Numeric cdfValue2(const unsigned* indexS, unsigned indexLenS) const
1771  {return static_cast<Numeric>((*this).template cdfValue<
1772  typename PreciseType<Numeric>::type>(indexS, indexLenS));}
1773 
1774  inline void convertToLastDimCdf2(ArrayND* sumSlice, bool b)
1775  {(*this).template convertToLastDimCdf<
1776  typename PreciseType<Numeric>::type>(sumSlice, b);}
1777 
1778  inline bool isClose2(const ArrayND& r, double eps) const
1779  {return isClose(r, eps);}
1780 
1781  inline bool isShapeCompatible2(const ArrayND& r) const
1782  {return isShapeCompatible(r);}
1783 
1784  inline void exportSlice2(
1785  ArrayND* slice,
1786  const unsigned* fixedIndicesS, unsigned nFixedIndicesS,
1787  const unsigned* fixedIndexValuesS, unsigned nFixedValuesS) const
1788  {
1789  if (nFixedIndicesS != nFixedValuesS) throw std::invalid_argument(
1790  "In npstat::ArrayND::exportSlice2: incompatible inputs");
1791  exportSlice(slice, fixedIndicesS, fixedIndexValuesS, nFixedIndicesS);
1792  }
1793 
1794  inline void exportMemSlice2(Numeric* slice, unsigned long len,
1795  const unsigned* fixedIndices,
1796  const unsigned* fixedIndexValues,
1797  unsigned nFixedInd) const
1798  {exportMemSlice(slice, len, fixedIndices,
1799  fixedIndexValues, nFixedInd);}
1800 
1801  inline void importSlice2(
1802  const ArrayND& slice,
1803  const unsigned* fixedIndicesS, unsigned nFixedIndicesS,
1804  const unsigned* fixedIndexValuesS, unsigned nFixedValuesS)
1805  {
1806  if (nFixedIndicesS != nFixedValuesS) throw std::invalid_argument(
1807  "In npstat::ArrayND::importSlice2: incompatible inputs");
1808  importSlice(slice, fixedIndicesS, fixedIndexValuesS, nFixedIndicesS);
1809  }
1810 
1811  inline void importMemSlice2(const Numeric* slice, unsigned long len,
1812  const unsigned* fixedIndices,
1813  const unsigned* fixedIndexValues,
1814  unsigned nFixedInd)
1815  {importMemSlice(slice, len, fixedIndices,
1816  fixedIndexValues, nFixedInd);}
1817 
1818  inline ArrayND& multiplyBySlice2(
1819  const ArrayND<proper_double>& slice,
1820  const unsigned* fixedIndicesS, unsigned nFixedIndicesS)
1821  {return multiplyBySlice(slice, fixedIndicesS, nFixedIndicesS);}
1822 
1823  inline ArrayND subrange(const ArrayRange& range)
1824  {return ArrayND(*this, range);}
1825 
1826  inline ArrayND slice(const unsigned* indexS, unsigned indexLenS)
1827  {return ArrayND(*this, indexS, indexLenS);}
1828 
1829  inline void rotate2(const unsigned* shiftsX, unsigned lenShiftsX,
1830  ArrayND* rotated) const
1831  {rotate(shiftsX, lenShiftsX, rotated);}
1832 
1833  inline void mirror2(const unsigned* mirrorDims, unsigned mirrorLen,
1834  ArrayND* mirrored) const
1835  {mirror(mirrorDims, mirrorLen, mirrored);}
1836 
1837  inline void exportSubrange2(const unsigned* cornerS, unsigned lenCornerS,
1838  ArrayND* to) const
1839  {exportSubrange(cornerS, lenCornerS, to);}
1840 
1841  inline void importSubrange2(const unsigned* cornerS, unsigned lenCornerS,
1842  const ArrayND& from)
1843  {importSubrange(cornerS, lenCornerS, from);}
1844 
1845  inline void multiMirror2(ArrayND* out) const
1846  {multiMirror(out);}
1847 #endif // SWIG
1848  };
1849 
1850  //@{
1851  /**
1852  // This function allows you to manage external data memory
1853  // using ArrayND objects. It can be used, for example, to create
1854  // arrays which live completely on the stack and still manage
1855  // sizeable chunks of already allocated memory. It is up to the
1856  // user of this function to ensure that the size of the memory
1857  // buffer is consistent with the shape of the array.
1858  //
1859  // Note that the responsibility to manage external data passes
1860  // to another ArrayND through a move constructor or through
1861  // a move assignment operator but not through a normal copy
1862  // constructor or assignment operator. Because of this feature,
1863  // this function works only with compilers supporting C++11.
1864  */
1865  template <typename Numeric>
1867  const unsigned* shape, unsigned dim);
1868  template <typename Numeric>
1869  ArrayND<Numeric> externalMemArrayND(Numeric* data, const ArrayShape& shape);
1870 
1871  template <typename Numeric>
1872  ArrayND<Numeric> externalMemArrayND(Numeric* data, unsigned n0);
1873 
1874  template <typename Numeric>
1875  ArrayND<Numeric> externalMemArrayND(Numeric* data, unsigned n0, unsigned n1);
1876 
1877  template <typename Numeric>
1878  ArrayND<Numeric> externalMemArrayND(Numeric* data, unsigned n0, unsigned n1,
1879  unsigned n2);
1880  template <typename Numeric>
1881  ArrayND<Numeric> externalMemArrayND(Numeric* data, unsigned n0, unsigned n1,
1882  unsigned n2, unsigned n3);
1883  template <typename Numeric>
1884  ArrayND<Numeric> externalMemArrayND(Numeric* data, unsigned n0, unsigned n1,
1885  unsigned n2, unsigned n3, unsigned n4);
1886  template <typename Numeric>
1887  ArrayND<Numeric> externalMemArrayND(Numeric* data, unsigned n0, unsigned n1,
1888  unsigned n2, unsigned n3, unsigned n4,
1889  unsigned n5);
1890  template <typename Numeric>
1891  ArrayND<Numeric> externalMemArrayND(Numeric* data, unsigned n0, unsigned n1,
1892  unsigned n2, unsigned n3, unsigned n4,
1893  unsigned n5, unsigned n6);
1894  template <typename Numeric>
1895  ArrayND<Numeric> externalMemArrayND(Numeric* data, unsigned n0, unsigned n1,
1896  unsigned n2, unsigned n3, unsigned n4,
1897  unsigned n5, unsigned n6, unsigned n7);
1898  template <typename Numeric>
1899  ArrayND<Numeric> externalMemArrayND(Numeric* data, unsigned n0, unsigned n1,
1900  unsigned n2, unsigned n3, unsigned n4,
1901  unsigned n5, unsigned n6, unsigned n7,
1902  unsigned n8);
1903  template <typename Numeric>
1904  ArrayND<Numeric> externalMemArrayND(Numeric* data, unsigned n0, unsigned n1,
1905  unsigned n2, unsigned n3, unsigned n4,
1906  unsigned n5, unsigned n6, unsigned n7,
1907  unsigned n8, unsigned n9);
1908 
1909  template <typename Numeric>
1910  CPP11_auto_ptr<ArrayND<Numeric> > allocExternalMemArrayND(
1911  Numeric* data, const unsigned* shape, unsigned dim);
1912 
1913  template <typename Numeric>
1914  CPP11_auto_ptr<ArrayND<Numeric> > allocExternalMemArrayND(
1915  Numeric* data, const ArrayShape& shape);
1916  //@}
1917 
1918  // These functions are external because they are not
1919  // necessarily meaningful for all array element types
1920 
1921  /** Minimum array element */
1922  template<class Arr>
1923  typename Arr::value_type arrayMin(const Arr& arr);
1924 
1925  /** Index of the minimum array element */
1926  template<class Arr>
1927  ArrayShape arrayArgmin(const Arr& arr);
1928 
1929  /** Maximum array element */
1930  template<class Arr>
1931  typename Arr::value_type arrayMax(const Arr& arr);
1932 
1933  /** Index of the maximum array element */
1934  template<class Arr>
1935  ArrayShape arrayArgmax(const Arr& arr);
1936 
1937  /** Minimum and maximum array element */
1938  template<class Arr>
1939  std::pair<typename Arr::value_type, typename Arr::value_type>
1940  arrayMinMax(const Arr& arr);
1941 
1942  /** Check if all array elements are non-negative */
1943  template<class Arr>
1944  bool arrayIsNonNegative(const Arr& arr);
1945 
1946  /**
1947  // Check whether all array elements are non-negative and,
1948  // in addition, there is at least one positive element
1949  */
1950  template<class Arr>
1951  bool arrayIsDensity(const Arr& arr);
1952 }
1953 
1954 template <typename Num2, typename Numeric, unsigned StackLen, unsigned StackDim>
1956 operator*(const Num2& l, const npstat::ArrayND<Numeric,StackLen,StackDim>& r)
1957 {
1958  return r*l;
1959 }
1960 
1961 #include "npstat/nm/ArrayND.icc"
1962 
1963 #endif // NPSTAT_ARRAYND_HH_
Interface definition for functors used to make array projections.
Interface for piecemeal processing of a data collection.
npstat::ArrayND< typename npstat::LongerType< Numeric, Num2 >::type, npstat::BiggerUInt< StackLen, Len2 >::value, npstat::BiggerUInt< StackDim, Dim2 >::value > operator+(const npstat::ArrayND< Numeric, StackLen, StackDim > &l, const npstat::ArrayND< Num2, Len2, Dim2 > &r)
Multidimensional range of array indices.
Compile-time deduction of an appropriate numeric type for simple algebraic operations.
Compile-time deduction of an appropriate precise numeric type.
Compile-time deduction of the underlying floating point type from the given complex type.
Interface definitions and concrete simple functors for a variety of functor-based calculations.
Definition: ArrayND.hh:93
ArrayND & makeNonNegative()
ArrayND & multiplyBySlice(const ArrayND< Num2, Len2, Dim2 > &slice, const unsigned *fixedIndices, unsigned nFixedIndices)
Definition: ArrayND.hh:846
ArrayND & functorFill(Functor f)
void flatCircularScan(ArrayND< Num2, Len2, Dim2 > &other, const unsigned *thisCorner, const unsigned *range, const unsigned *otherCorner, unsigned arrLen, Functor binaryFunct)
Numeric & at()
ArrayND & reshape(const ArrayND< Num2, Len2, Dim2 > &r)
ArrayND(const ArrayND< Num2, Len2, Dim2 > &from, const ArrayRange &fromRange)
unsigned long linearIndex(const unsigned *idx, unsigned idxLen) const
void convertLinearIndex(unsigned long l, unsigned *index, unsigned indexLen) const
void project(ArrayND< Num2, Len2, Dim2 > *projection, AbsArrayProjector< Numeric, Num3 > &projector, const unsigned *projectedIndices, unsigned nProjectedIndices) const
bool isShapeCompatible(const ArrayND< Num2, Len2, Dim2 > &r) const
Numeric & closest(const double *x, unsigned xDim)
void dualCircularScan(ArrayND< Num2, Len2, Dim2 > &other, const unsigned *thisCorner, const unsigned *range, const unsigned *otherCorner, unsigned arrLen, Functor binaryFunct)
ArrayND & operator=(const ArrayND< Num2, Len2, Dim2 > &)
ArrayND & constFill(Numeric c)
double maxAbsDifference(const ArrayND< Numeric, Len2, Dim2 > &) const
unsigned rank() const
Definition: ArrayND.hh:329
ArrayND & addmul(const ArrayND< Num2, Len2, Dim2 > &r, const Num3 &c)
void importMemSlice(const Num2 *buffer, unsigned long bufLen, const unsigned *fixedIndices, const unsigned *fixedIndexValues, unsigned nFixedIndices)
Definition: ArrayND.hh:820
ArrayShape shape() const
ArrayRange fullRange() const
void jointScan(ArrayND< Num2, Len2, Dim2 > &other, Functor binaryFunct)
Numeric interpolate3(const double *x, unsigned xDim) const
ArrayND(const ArrayND &)
void addToProjection(ArrayND< Num2, Len2, Dim2 > *projection, AbsArrayProjector< Numeric, Num3 > &projector, const unsigned *projectedIndices, unsigned nProjectedIndices) const
ArrayND & apply(Functor f)
ArrayND & makeUnit()
ArrayND(const ArrayND< Num2, Len2, Dim2 > &, Functor f)
void circularFlatScan(ArrayND< Num2, Len2, Dim2 > &other, const unsigned *thisCorner, const unsigned *range, const unsigned *otherCorner, unsigned arrLen, Functor binaryFunct)
void processSubrange(AbsArrayProjector< Numeric, Num2 > &f, const BoxND< Integer > &subrange) const
ArrayND operator+() const
ArrayND & scanInPlace(Functor f)
ArrayND & operator=(ArrayND &&)
const unsigned long * strides() const
Definition: ArrayND.hh:350
bool isCompatible(const ArrayShape &shape) const
void mirror(const unsigned *mirrorDims, unsigned mirrorLen, ArrayND< Num2, Len2, Dim2 > *out) const
Numeric & operator()()
ArrayND transpose(unsigned pos1, unsigned pos2) const
ArrayND & assign(const ArrayND< Num2, Len2, Dim2 > &, Functor f)
ArrayND transpose() const
void exportSubrange(const unsigned *fromCorner, unsigned lenCorner, ArrayND< Num2, Len2, Dim2 > *dest) const
ArrayND outer(const ArrayND< Num2, Len2, Dim2 > &r) const
ArrayND & setData(const Num2 *data, unsigned long dataLength)
ArrayND dot(const ArrayND< Num2, Len2, Dim2 > &r) const
void rotate(const unsigned *shifts, unsigned lenShifts, ArrayND< Num2, Len2, Dim2 > *rotated) const
Numeric & cl()
ArrayND(unsigned n0)
ArrayRange nonZeroRange() const
void convertToLastDimCdf(ArrayND *sumSlice, bool useTrapezoids)
bool isNonZero() const
ArrayND & uninitialize()
bool isClose(const ArrayND< Num2, Len2, Dim2 > &r, double eps) const
ArrayND(const ArrayND< Num2, Len2, Dim2 > &slicedArray, const unsigned *indices, unsigned nIndices)
void jointMemSliceScan(Num2 *buffer, unsigned long bufLen, const unsigned *fixedIndices, const unsigned *fixedIndexValues, unsigned nFixedIndices, Functor binaryFunct)
unsigned long length() const
Definition: ArrayND.hh:320
unsigned minimumSpan() const
ArrayND & operator*=(const Num2 &r)
ArrayND(const ArrayND< Num2, Len2, Dim2 > &)
void exportMemSlice(Num2 *buffer, unsigned long bufLen, const unsigned *fixedIndices, const unsigned *fixedIndexValues, unsigned nFixedIndices) const
Definition: ArrayND.hh:793
bool operator==(const ArrayND< Numeric, Len2, Dim2 > &) const
ArrayND(ArrayND &&)
ArrayND(const ArrayND< Num2, Len2, Dim2 > &from, const ArrayRange &fromRange, Functor f)
Numeric & linearValue(unsigned long index)
ArrayND operator/(const Num2 &r) const
ArrayND & clear()
Numeric & valueAt(const unsigned *index, unsigned indexLen)
unsigned makeCopulaSteps(double tolerance, unsigned maxIterations)
ArrayND(const ArrayShape &shape)
Num2 cdfValue(const unsigned *index, unsigned indexLen) const
ArrayND & reshape(const ArrayShape &newShape)
void applySlice(ArrayND< Num2, Len2, Dim2 > &slice, const unsigned *fixedIndices, unsigned nFixedIndices, Functor binaryFunct)
void coarseAverage(unsigned idim, unsigned n, ArrayND< Num2, Len2, Dim2 > *result) const
Numeric & linearValueAt(unsigned long index)
ArrayND(const ArrayND< Num1, Len1, Dim1 > &a1, const ArrayND< Num2, Len2, Dim2 > &a2)
bool isShapeKnown() const
Definition: ArrayND.hh:326
void jointSliceScan(ArrayND< Num2, Len2, Dim2 > &slice, const unsigned *fixedIndices, const unsigned *fixedIndexValues, unsigned nFixedIndices, Functor binaryFunct)
const Numeric * data() const
Definition: ArrayND.hh:323
Num2 sum() const
void coarseSum(unsigned idim, unsigned n, ArrayND< Num2, Len2, Dim2 > *result) const
Numeric & value(const unsigned *index, unsigned indexLen)
bool isZero() const
ArrayND derivative(double scale=1.0) const
const unsigned * shapeData() const
Definition: ArrayND.hh:335
ArrayND & linearFill(const double *coeff, unsigned coeffLen, double c)
ArrayND operator*(const Num2 &r) const
unsigned span(unsigned dim) const
void exportSlice(ArrayND< Num2, Len2, Dim2 > *slice, const unsigned *fixedIndices, const unsigned *fixedIndexValues, unsigned nFixedIndices) const
Definition: ArrayND.hh:777
ArrayND contract(unsigned pos1, unsigned pos2) const
void multiMirror(ArrayND< Num2, Len2, Dim2 > *out) const
Num2 sumsq() const
ArrayND cdfArray(double scale=1.0) const
void importSubrange(const unsigned *fromCorner, unsigned lenCorner, const ArrayND< Num2, Len2, Dim2 > &from)
ArrayND marginalize(const ArrayND< Num2, Len2, Dim2 > &prior, const unsigned *indexMap, unsigned mapLen) const
Numeric interpolate1(const double *x, unsigned xDim) const
ArrayND & operator=(const ArrayND &)
void importSlice(const ArrayND< Num2, Len2, Dim2 > &slice, const unsigned *fixedIndices, const unsigned *fixedIndexValues, unsigned nFixedIndices)
Definition: ArrayND.hh:805
void jointSubrangeScan(ArrayND< Num2, Len2, Dim2 > &other, const unsigned *thisCorner, const unsigned *range, const unsigned *otherCorner, unsigned arrLen, Functor binaryFunct)
unsigned maximumSpan() const
ArrayShape sliceShape(const unsigned *fixedIndices, unsigned nFixedIndices) const
gs::ClassId classId() const
Definition: ArrayND.hh:1125
bool operator!=(const ArrayND< Numeric, Len2, Dim2 > &) const
Definition: AbsArrayProjector.hh:14
std::vector< unsigned > ArrayShape
Definition: ArrayShape.hh:21
bool arrayIsNonNegative(const Arr &arr)
bool arrayIsDensity(const Arr &arr)
ArrayShape arrayArgmin(const Arr &arr)
ArrayND< Numeric > externalMemArrayND(Numeric *data, const unsigned *shape, unsigned dim)
Arr::value_type arrayMax(const Arr &arr)
ArrayShape arrayArgmax(const Arr &arr)
Arr::value_type arrayMin(const Arr &arr)
std::pair< typename Arr::value_type, typename Arr::value_type > arrayMinMax(const Arr &arr)
Definition: AbsArrayProjector.hh:21
Definition: AbsVisitor.hh:20
Definition: ArrayRange.hh:24
Definition: LongerType.hh:32
Definition: BoxND.hh:25
Definition: SimpleFunctors.hh:664
Definition: SimpleFunctors.hh:748
Definition: SimpleFunctors.hh:756