CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_6_1_2_SLHC2/src/JetMETCorrections/InterpolationTables/interface/ArrayND.h

Go to the documentation of this file.
00001 #ifndef NPSTAT_ARRAYND_HH_
00002 #define NPSTAT_ARRAYND_HH_
00003 
00014 #include <cassert>
00015 
00016 #include "Alignment/Geners/interface/ClassId.hh"
00017 
00018 #include "JetMETCorrections/InterpolationTables/interface/SimpleFunctors.h"
00019 #include "JetMETCorrections/InterpolationTables/interface/ArrayRange.h"
00020 #include "JetMETCorrections/InterpolationTables/interface/AbsArrayProjector.h"
00021 #include "JetMETCorrections/InterpolationTables/interface/AbsVisitor.h"
00022 #include "JetMETCorrections/InterpolationTables/interface/PreciseType.h"
00023 #include "JetMETCorrections/InterpolationTables/interface/ProperDblFromCmpl.h"
00024 
00025 namespace npstat {
00047     template <typename Numeric, unsigned StackLen=1U, unsigned StackDim=10U>
00048     class ArrayND
00049     {
00050         template <typename Num2, unsigned Len2, unsigned Dim2>
00051         friend class ArrayND;
00052 
00053     public:
00054         typedef Numeric value_type;
00055         typedef typename ProperDblFromCmpl<Numeric>::type proper_double;
00056 
00071         ArrayND();
00072 
00074 
00082         explicit ArrayND(const ArrayShape& shape);
00083         ArrayND(const unsigned* shape, unsigned dim);
00085 
00087         ArrayND(const ArrayND&);
00088 
00097         template <typename Num2, unsigned Len2, unsigned Dim2>
00098         ArrayND(const ArrayND<Num2, Len2, Dim2>&);
00099 
00104         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
00105         ArrayND(const ArrayND<Num2, Len2, Dim2>&, Functor f);
00106 
00108         template <typename Num2, unsigned Len2, unsigned Dim2>
00109         ArrayND(const ArrayND<Num2, Len2, Dim2>& from,
00110                 const ArrayRange& fromRange);
00111 
00113         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
00114         ArrayND(const ArrayND<Num2, Len2, Dim2>& from,
00115                 const ArrayRange& fromRange, Functor f);
00116 
00128         template <typename Num2, unsigned Len2, unsigned Dim2>
00129         ArrayND(const ArrayND<Num2, Len2, Dim2>& slicedArray,
00130                 const unsigned *indices, unsigned nIndices);
00131 
00133         template <typename Num1, unsigned Len1, unsigned Dim1,
00134                   typename Num2, unsigned Len2, unsigned Dim2>
00135         ArrayND(const ArrayND<Num1, Len1, Dim1>& a1,
00136                 const ArrayND<Num2, Len2, Dim2>& a2);
00137 
00139 
00143         explicit ArrayND(unsigned n0);
00144         ArrayND(unsigned n0, unsigned n1);
00145         ArrayND(unsigned n0, unsigned n1, unsigned n2);
00146         ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3);
00147         ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
00148                 unsigned n4);
00149         ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
00150                 unsigned n4, unsigned n5);
00151         ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
00152                 unsigned n4, unsigned n5, unsigned n6);
00153         ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
00154                 unsigned n4, unsigned n5, unsigned n6, unsigned n7);
00155         ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
00156                 unsigned n4, unsigned n5, unsigned n6, unsigned n7,
00157                 unsigned n8);
00158         ArrayND(unsigned n0, unsigned n1, unsigned n2, unsigned n3,
00159                 unsigned n4, unsigned n5, unsigned n6, unsigned n7,
00160                 unsigned n8, unsigned n9);
00162 
00164         ~ArrayND();
00165 
00174         ArrayND& operator=(const ArrayND&);
00175 
00177         template <typename Num2, unsigned Len2, unsigned Dim2>
00178         ArrayND& operator=(const ArrayND<Num2,Len2,Dim2>&);
00179 
00181         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
00182         ArrayND& assign(const ArrayND<Num2, Len2, Dim2>&, Functor f);
00183 
00189         ArrayND& uninitialize();
00190 
00192 
00197         Numeric& value(const unsigned *index, unsigned indexLen);
00198         const Numeric& value(const unsigned *index, unsigned indexLen) const;
00200 
00202 
00206         Numeric& valueAt(const unsigned *index, unsigned indexLen);
00207         const Numeric& valueAt(const unsigned *index, unsigned indexLen) const;
00209 
00211 
00212         Numeric& linearValue(unsigned long index);
00213         const Numeric& linearValue(unsigned long index) const;
00215 
00217 
00218         Numeric& linearValueAt(unsigned long index);
00219         const Numeric& linearValueAt(unsigned long index) const;
00221 
00223         void convertLinearIndex(unsigned long l, unsigned* index,
00224                                 unsigned indexLen) const;
00225 
00227         unsigned long linearIndex(const unsigned* idx, unsigned idxLen) const;
00228 
00229         // Some inspectors
00231         inline unsigned long length() const {return len_;}
00232 
00234         inline const Numeric* data() const {return data_;}
00235 
00237         inline bool isShapeKnown() const {return shapeIsKnown_;}
00238 
00240         inline unsigned rank() const {return dim_;}
00241 
00243         ArrayShape shape() const;
00244 
00246         inline const unsigned *shapeData() const {return shape_;}
00247 
00249         ArrayRange fullRange() const;
00250 
00252         unsigned span(unsigned dim) const;
00253 
00255         unsigned maximumSpan() const;
00256 
00258         unsigned minimumSpan() const;
00259 
00261         inline const unsigned long* strides() const {return strides_;}
00262 
00264         bool isZero() const;
00265 
00271         bool isDensity() const;
00272 
00274         template <typename Num2>
00275         ArrayND& setData(const Num2* data, unsigned long dataLength);
00276 
00278         template <unsigned Len2, unsigned Dim2>
00279         bool operator==(const ArrayND<Numeric,Len2,Dim2>&) const;
00280 
00282         template <unsigned Len2, unsigned Dim2>
00283         bool operator!=(const ArrayND<Numeric,Len2,Dim2>&) const;
00284 
00286         template <unsigned Len2, unsigned Dim2>
00287         double maxAbsDifference(const ArrayND<Numeric,Len2,Dim2>&) const;
00288 
00290         ArrayND operator+() const;
00291 
00293         ArrayND operator-() const;
00294 
00296         template <unsigned Len2, unsigned Dim2>
00297         ArrayND operator+(const ArrayND<Numeric,Len2,Dim2>& r) const;
00298 
00300         template <unsigned Len2, unsigned Dim2>
00301         ArrayND operator-(const ArrayND<Numeric,Len2,Dim2>& r) const;
00302 
00304         template <typename Num2>
00305         ArrayND operator*(const Num2& r) const;
00306 
00308         template <typename Num2>
00309         ArrayND operator/(const Num2& r) const;
00310 
00312 
00316         template <typename Num2>
00317         ArrayND& operator*=(const Num2& r);
00318 
00319         template <typename Num2>
00320         ArrayND& operator/=(const Num2& r);
00321 
00322         template <typename Num2, unsigned Len2, unsigned Dim2>
00323         ArrayND& operator+=(const ArrayND<Num2,Len2,Dim2>& r);
00324 
00325         template <typename Num2, unsigned Len2, unsigned Dim2>
00326         ArrayND& operator-=(const ArrayND<Num2,Len2,Dim2>& r);
00328 
00330         template <typename Num3, typename Num2, unsigned Len2, unsigned Dim2>
00331         ArrayND& addmul(const ArrayND<Num2,Len2,Dim2>& r, const Num3& c);
00332 
00334         template <typename Num2, unsigned Len2, unsigned Dim2>
00335         ArrayND outer(const ArrayND<Num2,Len2,Dim2>& r) const;
00336 
00341         ArrayND contract(unsigned pos1, unsigned pos2) const;
00342 
00348         template <typename Num2, unsigned Len2, unsigned Dim2>
00349         ArrayND dot(const ArrayND<Num2,Len2,Dim2>& r) const;
00350 
00365         template <typename Num2, unsigned Len2, unsigned Dim2>
00366         ArrayND marginalize(const ArrayND<Num2,Len2,Dim2>& prior,
00367                             const unsigned* indexMap, unsigned mapLen) const;
00368 
00370         ArrayND transpose(unsigned pos1, unsigned pos2) const;
00371 
00373         ArrayND transpose() const;
00374 
00381         template <typename Num2>
00382         Num2 sum() const;
00383 
00388         template <typename Num2>
00389         Num2 sumsq() const;
00390 
00399         template <typename Num2>
00400         ArrayND derivative(double scale=1.0) const;
00401 
00406         template <typename Num2>
00407         ArrayND cdfArray(double scale=1.0) const;
00408 
00413         template <typename Num2>
00414         Num2 cdfValue(const unsigned *index, unsigned indexLen) const;
00415 
00427         template <typename Num2>
00428         void convertToLastDimCdf(ArrayND* sumSlice, bool useTrapezoids);
00429 
00431         Numeric min() const;
00432 
00434         Numeric min(unsigned *index, unsigned indexLen) const;
00435 
00437         Numeric max() const;
00438 
00440         Numeric max(unsigned *index, unsigned indexLen) const;
00441 
00443 
00451         Numeric& closest(const double *x, unsigned xDim);
00452         const Numeric& closest(const double *x, unsigned xDim) const;
00454 
00463         Numeric interpolate1(const double *x, unsigned xDim) const;
00464 
00471         Numeric interpolate3(const double *x, unsigned xDim) const;
00472 
00482         template <class Functor>
00483         ArrayND& apply(Functor f);
00484 
00492         template <class Functor>
00493         ArrayND& scanInPlace(Functor f);
00494 
00496         ArrayND& constFill(Numeric c);
00497 
00499         ArrayND& clear();
00500 
00507         ArrayND& linearFill(const double* coeff, unsigned coeffLen, double c);
00508 
00515         template <class Functor>
00516         ArrayND& functorFill(Functor f);
00517 
00524         ArrayND& makeUnit();
00525 
00527         ArrayND& makeNonNegative();
00528 
00538         unsigned makeCopulaSteps(double tolerance, unsigned maxIterations);
00539 
00544         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
00545         void jointScan(ArrayND<Num2, Len2, Dim2>& other, Functor binaryFunct);
00546 
00549         template <typename Num2, unsigned Len2, unsigned Dim2>
00550         inline ArrayND& inPlaceMul(const ArrayND<Num2,Len2,Dim2>& r)
00551         {
00552             jointScan(const_cast<ArrayND<Num2,Len2,Dim2>&>(r),
00553                       multeq_left<Numeric,Num2>());
00554             return *this;
00555         }
00556 
00574         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
00575         void jointSubrangeScan(ArrayND<Num2, Len2, Dim2>& other,
00576                                const unsigned* thisCorner,
00577                                const unsigned* range,
00578                                const unsigned* otherCorner,
00579                                unsigned arrLen,
00580                                Functor binaryFunct);
00581 
00587         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
00588         void dualCircularScan(ArrayND<Num2, Len2, Dim2>& other,
00589                               const unsigned* thisCorner,
00590                               const unsigned* range,
00591                               const unsigned* otherCorner,
00592                               unsigned arrLen,
00593                               Functor binaryFunct);
00594 
00599         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
00600         void flatCircularScan(ArrayND<Num2, Len2, Dim2>& other,
00601                               const unsigned* thisCorner,
00602                               const unsigned* range,
00603                               const unsigned* otherCorner,
00604                               unsigned arrLen,
00605                               Functor binaryFunct);
00606 
00611         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
00612         void circularFlatScan(ArrayND<Num2, Len2, Dim2>& other,
00613                               const unsigned* thisCorner,
00614                               const unsigned* range,
00615                               const unsigned* otherCorner,
00616                               unsigned arrLen,
00617                               Functor binaryFunct);
00618 
00625         template <typename Num2, typename Integer>
00626         void processSubrange(AbsArrayProjector<Numeric,Num2>& f,
00627                              const BoxND<Integer>& subrange) const;
00628 
00636         template <typename Num2, unsigned Len2, unsigned Dim2>
00637         void exportSubrange(const unsigned* fromCorner, unsigned lenCorner,
00638                             ArrayND<Num2, Len2, Dim2>* dest) const;
00639 
00641         template <typename Num2, unsigned Len2, unsigned Dim2>
00642         void importSubrange(const unsigned* fromCorner, unsigned lenCorner,
00643                             const ArrayND<Num2, Len2, Dim2>& from);
00644 
00650         template <typename Num2, unsigned Len2, unsigned Dim2>
00651         bool isClose(const ArrayND<Num2,Len2,Dim2>& r, double eps) const;
00652 
00654         bool isCompatible(const ArrayShape& shape) const;
00655 
00660         template <typename Num2, unsigned Len2, unsigned Dim2>
00661         bool isShapeCompatible(const ArrayND<Num2,Len2,Dim2>& r) const;
00662 
00672         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
00673         void jointSliceScan(ArrayND<Num2,Len2,Dim2>& slice,
00674                             const unsigned *fixedIndices,
00675                             const unsigned *fixedIndexValues,
00676                             unsigned nFixedIndices,
00677                             Functor binaryFunct);
00678 
00680         template <typename Num2, unsigned Len2, unsigned Dim2>
00681         inline void exportSlice(ArrayND<Num2,Len2,Dim2>* slice,
00682                                 const unsigned *fixedIndices,
00683                                 const unsigned *fixedIndexValues,
00684                                 unsigned nFixedIndices) const
00685         {
00686             assert(slice);
00687             (const_cast<ArrayND*>(this))->jointSliceScan(
00688                 *slice, fixedIndices, fixedIndexValues, nFixedIndices,
00689                 scast_assign_right<Numeric,Num2>());
00690         }
00691 
00693         template <typename Num2, unsigned Len2, unsigned Dim2>
00694         inline void importSlice(const ArrayND<Num2,Len2,Dim2>& slice,
00695                                 const unsigned *fixedIndices,
00696                                 const unsigned *fixedIndexValues,
00697                                 unsigned nFixedIndices)
00698         {
00699             jointSliceScan(const_cast<ArrayND<Num2,Len2,Dim2>&>(slice),
00700                            fixedIndices, fixedIndexValues, nFixedIndices,
00701                            scast_assign_left<Numeric,Num2>());
00702         }
00703 
00711         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
00712         void applySlice(ArrayND<Num2,Len2,Dim2>& slice,
00713                         const unsigned *fixedIndices, unsigned nFixedIndices,
00714                         Functor binaryFunct);
00715 
00720         template <typename Num2, unsigned Len2, unsigned Dim2>
00721         inline ArrayND& multiplyBySlice(const ArrayND<Num2,Len2,Dim2>& slice,
00722                                         const unsigned *fixedIndices,
00723                                         unsigned nFixedIndices)
00724         {
00725             applySlice(const_cast<ArrayND<Num2,Len2,Dim2>&>(slice),
00726                        fixedIndices, nFixedIndices,
00727                        multeq_left<Numeric,Num2>());
00728             return *this;
00729         }
00730 
00732 
00739         template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
00740         void project(ArrayND<Num2,Len2,Dim2>* projection,
00741                      AbsArrayProjector<Numeric,Num3>& projector,
00742                      const unsigned *projectedIndices,
00743                      unsigned nProjectedIndices) const;
00744 
00745         template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
00746         void project(ArrayND<Num2,Len2,Dim2>* projection,
00747                      AbsVisitor<Numeric,Num3>& projector,
00748                      const unsigned *projectedIndices,
00749                      unsigned nProjectedIndices) const;
00751 
00753 
00758         template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
00759         void addToProjection(ArrayND<Num2,Len2,Dim2>* projection,
00760                              AbsArrayProjector<Numeric,Num3>& projector,
00761                              const unsigned *projectedIndices,
00762                              unsigned nProjectedIndices) const;
00763 
00764         template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
00765         void subtractFromProjection(ArrayND<Num2,Len2,Dim2>* projection,
00766                                     AbsArrayProjector<Numeric,Num3>& projector,
00767                                     const unsigned *projectedIndices,
00768                                     unsigned nProjectedIndices) const;
00769 
00770         template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
00771         void addToProjection(ArrayND<Num2,Len2,Dim2>* projection,
00772                              AbsVisitor<Numeric,Num3>& projector,
00773                              const unsigned *projectedIndices,
00774                              unsigned nProjectedIndices) const;
00775 
00776         template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
00777         void subtractFromProjection(ArrayND<Num2,Len2,Dim2>* projection,
00778                                     AbsVisitor<Numeric,Num3>& projector,
00779                                     const unsigned *projectedIndices,
00780                                     unsigned nProjectedIndices) const;
00782 
00788         template <typename Num2, unsigned Len2, unsigned Dim2>
00789         void rotate(const unsigned* shifts, unsigned lenShifts,
00790                     ArrayND<Num2, Len2, Dim2>* rotated) const;
00791 
00797         template <typename Num2, unsigned Len2, unsigned Dim2>
00798         void multiMirror(ArrayND<Num2, Len2, Dim2>* out) const;
00799 
00801 
00805         Numeric& operator()();
00806         const Numeric& operator()() const;
00807 
00808         Numeric& operator()(unsigned i0);
00809         const Numeric& operator()(unsigned i0) const;
00810 
00811         Numeric& operator()(unsigned i0, unsigned i1);
00812         const Numeric& operator()(unsigned i0, unsigned i1) const;
00813 
00814         Numeric& operator()(unsigned i0, unsigned i1, unsigned i2);
00815         const Numeric& operator()(unsigned i0, unsigned i1, unsigned i2) const;
00816 
00817         Numeric& operator()(unsigned i0, unsigned i1,
00818                             unsigned i2, unsigned i3);
00819         const Numeric& operator()(unsigned i0, unsigned i1,
00820                                   unsigned i2, unsigned i3) const;
00821 
00822         Numeric& operator()(unsigned i0, unsigned i1,
00823                             unsigned i2, unsigned i3, unsigned i4);
00824         const Numeric& operator()(unsigned i0, unsigned i1,
00825                                   unsigned i2, unsigned i3, unsigned i4) const;
00826 
00827         Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
00828                             unsigned i3, unsigned i4, unsigned i5);
00829         const Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
00830                                   unsigned i3, unsigned i4, unsigned i5) const;
00831 
00832         Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
00833                             unsigned i3, unsigned i4, unsigned i5,
00834                             unsigned i6);
00835         const Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
00836                                   unsigned i3, unsigned i4, unsigned i5,
00837                                   unsigned i6) const;
00838 
00839         Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
00840                             unsigned i3, unsigned i4, unsigned i5,
00841                             unsigned i6, unsigned i7);
00842         const Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
00843                                   unsigned i3, unsigned i4, unsigned i5,
00844                                   unsigned i6, unsigned i7) const;
00845 
00846         Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
00847                             unsigned i3, unsigned i4, unsigned i5,
00848                             unsigned i6, unsigned i7, unsigned i8);
00849         const Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
00850                                   unsigned i3, unsigned i4, unsigned i5,
00851                                   unsigned i6, unsigned i7, unsigned i8) const;
00852 
00853         Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
00854                             unsigned i3, unsigned i4, unsigned i5,
00855                             unsigned i6, unsigned i7, unsigned i8,
00856                             unsigned i9);
00857         const Numeric& operator()(unsigned i0, unsigned i1, unsigned i2,
00858                                   unsigned i3, unsigned i4, unsigned i5,
00859                                   unsigned i6, unsigned i7, unsigned i8,
00860                                   unsigned i9) const;
00862 
00864 
00868         Numeric& at();
00869         const Numeric& at() const;
00870 
00871         Numeric& at(unsigned i0);
00872         const Numeric& at(unsigned i0) const;
00873 
00874         Numeric& at(unsigned i0, unsigned i1);
00875         const Numeric& at(unsigned i0, unsigned i1) const;
00876 
00877         Numeric& at(unsigned i0, unsigned i1, unsigned i2);
00878         const Numeric& at(unsigned i0, unsigned i1, unsigned i2) const;
00879 
00880         Numeric& at(unsigned i0, unsigned i1,
00881                     unsigned i2, unsigned i3);
00882         const Numeric& at(unsigned i0, unsigned i1,
00883                           unsigned i2, unsigned i3) const;
00884 
00885         Numeric& at(unsigned i0, unsigned i1,
00886                     unsigned i2, unsigned i3, unsigned i4);
00887         const Numeric& at(unsigned i0, unsigned i1,
00888                           unsigned i2, unsigned i3, unsigned i4) const;
00889 
00890         Numeric& at(unsigned i0, unsigned i1, unsigned i2,
00891                     unsigned i3, unsigned i4, unsigned i5);
00892         const Numeric& at(unsigned i0, unsigned i1, unsigned i2,
00893                           unsigned i3, unsigned i4, unsigned i5) const;
00894 
00895         Numeric& at(unsigned i0, unsigned i1, unsigned i2,
00896                     unsigned i3, unsigned i4, unsigned i5,
00897                     unsigned i6);
00898         const Numeric& at(unsigned i0, unsigned i1, unsigned i2,
00899                           unsigned i3, unsigned i4, unsigned i5,
00900                           unsigned i6) const;
00901 
00902         Numeric& at(unsigned i0, unsigned i1, unsigned i2,
00903                     unsigned i3, unsigned i4, unsigned i5,
00904                     unsigned i6, unsigned i7);
00905         const Numeric& at(unsigned i0, unsigned i1, unsigned i2,
00906                           unsigned i3, unsigned i4, unsigned i5,
00907                           unsigned i6, unsigned i7) const;
00908 
00909         Numeric& at(unsigned i0, unsigned i1, unsigned i2,
00910                     unsigned i3, unsigned i4, unsigned i5,
00911                     unsigned i6, unsigned i7, unsigned i8);
00912         const Numeric& at(unsigned i0, unsigned i1, unsigned i2,
00913                           unsigned i3, unsigned i4, unsigned i5,
00914                           unsigned i6, unsigned i7, unsigned i8) const;
00915 
00916         Numeric& at(unsigned i0, unsigned i1, unsigned i2,
00917                     unsigned i3, unsigned i4, unsigned i5,
00918                     unsigned i6, unsigned i7, unsigned i8,
00919                     unsigned i9);
00920         const Numeric& at(unsigned i0, unsigned i1, unsigned i2,
00921                           unsigned i3, unsigned i4, unsigned i5,
00922                           unsigned i6, unsigned i7, unsigned i8,
00923                           unsigned i9) const;
00925 
00927 
00931         Numeric& cl();
00932         const Numeric& cl() const;
00933 
00934         Numeric& cl(double x0);
00935         const Numeric& cl(double x0) const;
00936 
00937         Numeric& cl(double x0, double x1);
00938         const Numeric& cl(double x0, double x1) const;
00939 
00940         Numeric& cl(double x0, double x1, double x2);
00941         const Numeric& cl(double x0, double x1, double x2) const;
00942 
00943         Numeric& cl(double x0, double x1,
00944                     double x2, double x3);
00945         const Numeric& cl(double x0, double x1,
00946                           double x2, double x3) const;
00947 
00948         Numeric& cl(double x0, double x1,
00949                     double x2, double x3, double x4);
00950         const Numeric& cl(double x0, double x1,
00951                           double x2, double x3, double x4) const;
00952 
00953         Numeric& cl(double x0, double x1, double x2,
00954                     double x3, double x4, double x5);
00955         const Numeric& cl(double x0, double x1, double x2,
00956                           double x3, double x4, double x5) const;
00957 
00958         Numeric& cl(double x0, double x1, double x2,
00959                     double x3, double x4, double x5,
00960                     double x6);
00961         const Numeric& cl(double x0, double x1, double x2,
00962                           double x3, double x4, double x5,
00963                           double x6) const;
00964 
00965         Numeric& cl(double x0, double x1, double x2,
00966                     double x3, double x4, double x5,
00967                     double x6, double x7);
00968         const Numeric& cl(double x0, double x1, double x2,
00969                           double x3, double x4, double x5,
00970                           double x6, double x7) const;
00971 
00972         Numeric& cl(double x0, double x1, double x2,
00973                     double x3, double x4, double x5,
00974                     double x6, double x7, double x8);
00975         const Numeric& cl(double x0, double x1, double x2,
00976                           double x3, double x4, double x5,
00977                           double x6, double x7, double x8) const;
00978 
00979         Numeric& cl(double x0, double x1, double x2,
00980                     double x3, double x4, double x5,
00981                     double x6, double x7, double x8,
00982                     double x9);
00983         const Numeric& cl(double x0, double x1, double x2,
00984                           double x3, double x4, double x5,
00985                           double x6, double x7, double x8,
00986                           double x9) const;
00988 
00990 
00991         inline gs::ClassId classId() const {return gs::ClassId(*this);}
00992         bool write(std::ostream& of) const;
00994 
00995         static const char* classname();
00996         static inline unsigned version() {return 1;}
00997         static void restore(const gs::ClassId& id, std::istream& in,
00998                             ArrayND* array);
00999     private:
01000         Numeric localData_[StackLen];
01001         Numeric* data_;
01002 
01003         unsigned long localStrides_[StackDim];
01004         unsigned long *strides_;
01005 
01006         unsigned localShape_[StackDim];
01007         unsigned *shape_;
01008 
01009         unsigned long len_;
01010         unsigned dim_;
01011 
01012         bool shapeIsKnown_;
01013 
01014         // Basic initialization from unsigned* shape and dimensionality
01015         void buildFromShapePtr(const unsigned*, unsigned);
01016 
01017         // Build strides_ array out of the shape_ array
01018         void buildStrides();
01019 
01020         // Recursive implementation of nested loops for "linearFill"
01021         void linearFillLoop(unsigned level, double s0,
01022                             unsigned long idx, double shift,
01023                             const double* coeffs);
01024 
01025         // Recursive implementation of nested loops for "functorFill"
01026         template <class Functor>
01027         void functorFillLoop(unsigned level, unsigned long idx,
01028                              Functor f, unsigned* farg);
01029 
01030         // Recursive implementation of nested loops for "interpolate3"
01031         Numeric interpolateLoop(unsigned level, const double *x,
01032                                 const Numeric* base) const;
01033 
01034         // Recursive implementation of nested loops for the outer product
01035         template <typename Num1, unsigned Len1, unsigned Dim1,
01036                   typename Num2, unsigned Len2, unsigned Dim2>
01037         void outerProductLoop(unsigned level, unsigned long idx0,
01038                               unsigned long idx1, unsigned long idx2,
01039                               const ArrayND<Num1, Len1, Dim1>& a1,
01040                               const ArrayND<Num2, Len2, Dim2>& a2);
01041 
01042         // Recursive implementation of nested loops for contraction
01043         void contractLoop(unsigned thisLevel, unsigned resLevel,
01044                           unsigned pos1, unsigned pos2,
01045                           unsigned long idxThis, unsigned long idxRes,
01046                           ArrayND& result) const;
01047 
01048         // Recursive implementation of nested loops for transposition
01049         void transposeLoop(unsigned level, unsigned pos1, unsigned pos2,
01050                            unsigned long idxThis, unsigned long idxRes,
01051                            ArrayND& result) const;
01052 
01053         // Recursive implementation of nested loops for the dot product
01054         template <typename Num2, unsigned Len2, unsigned Dim2>
01055         void dotProductLoop(unsigned level, unsigned long idx0,
01056                             unsigned long idx1, unsigned long idx2,
01057                             const ArrayND<Num2, Len2, Dim2>& r,
01058                             ArrayND& result) const;
01059 
01060         // Recursive implementation of nested loops for marginalization
01061         template <typename Num2, unsigned Len2, unsigned Dim2>
01062         Numeric marginalizeInnerLoop(unsigned long idx,
01063                                      unsigned levelPr, unsigned long idxPr,
01064                                      const ArrayND<Num2,Len2,Dim2>& prior,
01065                                      const unsigned* indexMap) const;
01066         template <typename Num2, unsigned Len2, unsigned Dim2>
01067         void marginalizeLoop(unsigned level, unsigned long idx,
01068                              unsigned levelRes, unsigned long idxRes,
01069                              const ArrayND<Num2,Len2,Dim2>& prior,
01070                              const unsigned* indexMap, ArrayND& res) const;
01071 
01072         // Recursive implementation of nested loops for range copy
01073         // with functor modification of elements
01074         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
01075         void copyRangeLoopFunct(unsigned level, unsigned long idx0,
01076                                 unsigned long idx1,
01077                                 const ArrayND<Num2, Len2, Dim2>& r,
01078                                 const ArrayRange& range, Functor f);
01079 
01080         // Loop over subrange in such a way that the functor is called
01081         // only if indices on both sides are valid. The topology of both
01082         // arrays is that of the hyperplane (flat).
01083         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
01084         void commonSubrangeLoop(unsigned level, unsigned long idx0,
01085                                 unsigned long idx1,
01086                                 const unsigned* thisCorner,
01087                                 const unsigned* range,
01088                                 const unsigned* otherCorner,
01089                                 ArrayND<Num2, Len2, Dim2>& other,
01090                                 Functor binaryFunct);
01091 
01092         // Similar loop with the topology of the hypertorus for both
01093         // arrays (all indices of both arrays are wrapped around)
01094         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
01095         void dualCircularLoop(unsigned level, unsigned long idx0,
01096                               unsigned long idx1,
01097                               const unsigned* thisCorner,
01098                               const unsigned* range,
01099                               const unsigned* otherCorner,
01100                               ArrayND<Num2, Len2, Dim2>& other,
01101                               Functor binaryFunct);
01102 
01103         // Similar loop in which the topology of this array is assumed
01104         // to be flat and the topology of the destination array is that
01105         // of the hypertorus. Due to the asymmetry of the topologies,
01106         // "const" function is not provided (use const_cast as appropriate).
01107         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
01108         void flatCircularLoop(unsigned level, unsigned long idx0,
01109                               unsigned long idx1,
01110                               const unsigned* thisCorner,
01111                               const unsigned* range,
01112                               const unsigned* otherCorner,
01113                               ArrayND<Num2, Len2, Dim2>& other,
01114                               Functor binaryFunct);
01115 
01116         // Similar loop in which the topology of this array is assumed
01117         // to be hypertoroidal and the topology of the destination array
01118         // is flat.
01119         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
01120         void circularFlatLoop(unsigned level, unsigned long idx0,
01121                               unsigned long idx1,
01122                               const unsigned* thisCorner,
01123                               const unsigned* range,
01124                               const unsigned* otherCorner,
01125                               ArrayND<Num2, Len2, Dim2>& other,
01126                               Functor binaryFunct);
01127 
01128         // Slice compatibility verification
01129         template <typename Num2, unsigned Len2, unsigned Dim2>
01130         unsigned long verifySliceCompatibility(
01131             const ArrayND<Num2,Len2,Dim2>& slice,
01132             const unsigned *fixedIndices,
01133             const unsigned *fixedIndexValues,
01134             unsigned nFixedIndices) const;
01135 
01136         // Recursive implementation of nested loops for slice operations
01137         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
01138         void jointSliceLoop(unsigned level, unsigned long idx0,
01139                             unsigned level1, unsigned long idx1,
01140                             ArrayND<Num2,Len2,Dim2>& slice,
01141                             const unsigned *fixedIndices,
01142                             const unsigned *fixedIndexValues,
01143                             unsigned nFixedIndices, Functor binaryFunctor);
01144 
01145         // Recursive implementation of nested loops for "applySlice"
01146         template <typename Num2, class Functor>
01147         void scaleBySliceInnerLoop(unsigned level, unsigned long idx0,
01148                                    Num2& scale,
01149                                    const unsigned* projectedIndices,
01150                                    unsigned nProjectedIndices,
01151                                    Functor binaryFunct);
01152 
01153         template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
01154         void scaleBySliceLoop(unsigned level, unsigned long idx0,
01155                               unsigned level1, unsigned long idx1,
01156                               ArrayND<Num2,Len2,Dim2>& slice,
01157                               const unsigned *fixedIndices,
01158                               unsigned nFixedIndices,
01159                               Functor binaryFunct);
01160 
01161         // Recursive implementation of nested loops for projections
01162         template <typename Num2>
01163         void projectInnerLoop(unsigned level, unsigned long idx0,
01164                               unsigned* currentIndex,
01165                               AbsArrayProjector<Numeric,Num2>& projector,
01166                               const unsigned* projectedIndices,
01167                               unsigned nProjectedIndices) const;
01168 
01169         template <typename Num2, unsigned Len2, unsigned Dim2,
01170                   typename Num3, class Op>
01171         void projectLoop(unsigned level, unsigned long idx0,
01172                          unsigned level1, unsigned long idx1,
01173                          unsigned* currentIndex,
01174                          ArrayND<Num2,Len2,Dim2>* projection,
01175                          AbsArrayProjector<Numeric,Num3>& projector,
01176                          const unsigned* projectedIndices,
01177                          unsigned nProjectedIndices, Op fcn) const;
01178 
01179         // Note that "projectLoop2" is almost identical to "projectLoop"
01180         // while "projectInnerLoop2" is almost identical to "projectInnerLoop".
01181         // It would make a lot of sense to combine these functions into
01182         // the same code and then partially specialize the little piece
01183         // where the "AbsVisitor" or "AbsArrayProjector" is actually called.
01184         // Unfortunately, "AbsVisitor" and "AbsArrayProjector" are
01185         // templates themselves, and it is not possible in C++ to partially
01186         // specialize a function template (that is, even if we can specialize
01187         // on "AbsVisitor" vs. "AbsArrayProjector", there is no way to
01188         // specialize on their parameter types).
01189         template <typename Num2, unsigned Len2, unsigned Dim2,
01190                   typename Num3, class Op>
01191         void projectLoop2(unsigned level, unsigned long idx0,
01192                           unsigned level1, unsigned long idx1,
01193                           ArrayND<Num2,Len2,Dim2>* projection,
01194                           AbsVisitor<Numeric,Num3>& projector,
01195                           const unsigned* projectedIndices,
01196                           unsigned nProjectedIndices, Op fcn) const;
01197 
01198         template <typename Num2>
01199         void projectInnerLoop2(unsigned level, unsigned long idx0,
01200                                AbsVisitor<Numeric,Num2>& projector,
01201                                const unsigned* projectedIndices,
01202                                unsigned nProjectedIndices) const;
01203 
01204         template <typename Num2, typename Integer>
01205         void processSubrangeLoop(unsigned level, unsigned long idx0,
01206                                  unsigned* currentIndex,
01207                                  AbsArrayProjector<Numeric,Num2>& f,
01208                                  const BoxND<Integer>& subrange) const;
01209 
01210         // Sum of all points with the given index and below
01211         template <typename Accumulator>
01212         Accumulator sumBelowLoop(unsigned level, unsigned long idx0,
01213                                  const unsigned* limit) const;
01214 
01215         // Loop for "convertToLastDimCdf"
01216         template <typename Accumulator>
01217         void convertToLastDimCdfLoop(ArrayND* sumSlice, unsigned level,
01218                                      unsigned long idx0,
01219                                      unsigned long idxSlice,
01220                                      bool useTrapezoids);
01221 
01222         // Convert a coordinate into index.
01223         // No checking whether "idim" is within limits.
01224         unsigned coordToIndex(double coord, unsigned idim) const;
01225 
01226         // Verify that projection array is compatible with this one
01227         template <typename Num2, unsigned Len2, unsigned Dim2>
01228         void verifyProjectionCompatibility(
01229             const ArrayND<Num2,Len2,Dim2>& projection,
01230             const unsigned *projectedIndices,
01231             unsigned nProjectedIndices) const;
01232 
01233     };
01234 }
01235 
01236 #include <cmath>
01237 #include <climits>
01238 #include <algorithm>
01239 #include <sstream>
01240 #include "JetMETCorrections/InterpolationTables/interface/NpstatException.h"
01241 
01242 #include "Alignment/Geners/interface/GenericIO.hh"
01243 #include "Alignment/Geners/interface/IOIsUnsigned.hh"
01244 
01245 #include "JetMETCorrections/InterpolationTables/interface/allocators.h"
01246 
01247 #include "JetMETCorrections/InterpolationTables/interface/interpolate.h"
01248 #include "JetMETCorrections/InterpolationTables/interface/absDifference.h"
01249 #include "JetMETCorrections/InterpolationTables/interface/ComplexComparesFalse.h"
01250 #include "JetMETCorrections/InterpolationTables/interface/ComplexComparesAbs.h"
01251 
01252 #define me_macro_check_loop_prerequisites(METHOD, INNERLOOP)             \
01253     template<typename Numeric, unsigned Len, unsigned Dim>                   \
01254     template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>    \
01255     void ArrayND<Numeric,Len,Dim>:: METHOD (                                 \
01256         ArrayND<Num2, Len2, Dim2>& other,                                    \
01257         const unsigned* thisCorner,                                          \
01258         const unsigned* range,                                               \
01259         const unsigned* otherCorner,                                         \
01260         const unsigned arrLen,                                               \
01261         Functor binaryFunct)                                                 \
01262     {                                                                        \
01263         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(                     \
01264             "Initialize npstat::ArrayND before calling method \""            \
01265             #METHOD "\"");                                                   \
01266         if (!other.shapeIsKnown_) throw npstat::NpstatInvalidArgument(               \
01267             "In npstat::ArrayND::" #METHOD ": uninitialized argument array");\
01268         if (dim_ != other.dim_) throw npstat::NpstatInvalidArgument(                 \
01269             "In npstat::ArrayND::" #METHOD ": incompatible argument array rank");\
01270         if (arrLen != dim_) throw npstat::NpstatInvalidArgument(                     \
01271             "In npstat::ArrayND::" #METHOD ": incompatible index length");   \
01272         if (dim_)                                                            \
01273         {                                                                    \
01274             assert(thisCorner);                                              \
01275             assert(range);                                                   \
01276             assert(otherCorner);                                             \
01277             INNERLOOP (0U, 0UL, 0UL, thisCorner, range,                      \
01278                        otherCorner, other, binaryFunct);                     \
01279         }                                                                    \
01280         else                                                                 \
01281             binaryFunct(localData_[0], other.localData_[0]);                 \
01282     }
01283 
01284 namespace npstat {
01285     template<typename Numeric, unsigned Len, unsigned Dim>
01286     template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
01287     void ArrayND<Numeric,Len,Dim>::commonSubrangeLoop(
01288         unsigned level, unsigned long idx0,
01289         unsigned long idx1,
01290         const unsigned* thisCorner,
01291         const unsigned* range,
01292         const unsigned* otherCorner,
01293         ArrayND<Num2, Len2, Dim2>& r,
01294         Functor binaryFunct)
01295     {
01296         const unsigned imax = range[level];
01297 
01298         if (level == dim_ - 1)
01299         {
01300             Numeric* left = data_ + (idx0 + thisCorner[level]);
01301             Numeric* const lMax = data_ + (idx0 + shape_[level]);
01302             Num2* right = r.data_ + (idx1 + otherCorner[level]);
01303             Num2* const rMax = r.data_ + (idx1 + r.shape_[level]);
01304 
01305             for (unsigned i=0; i<imax && left<lMax && right<rMax; ++i)
01306                 binaryFunct(*left++, *right++);
01307         }
01308         else
01309         {
01310             const unsigned long leftStride = strides_[level];
01311             const unsigned long leftMax = idx0 + shape_[level]*leftStride;
01312             idx0 += thisCorner[level]*leftStride;
01313             const unsigned long rightStride = r.strides_[level];
01314             const unsigned long rightMax = idx1 + r.shape_[level]*rightStride;
01315             idx1 += otherCorner[level]*rightStride;
01316 
01317             for (unsigned i=0; i<imax && idx0 < leftMax && idx1 < rightMax;
01318                  ++i, idx0 += leftStride, idx1 += rightStride)
01319                 commonSubrangeLoop(level+1, idx0, idx1, thisCorner, range,
01320                                    otherCorner, r, binaryFunct);
01321         }
01322     }
01323 
01324     template<typename Numeric, unsigned Len, unsigned Dim>
01325     template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
01326     void ArrayND<Numeric,Len,Dim>::dualCircularLoop(
01327         unsigned level, unsigned long idx0,
01328         unsigned long idx1,
01329         const unsigned* thisCorner,
01330         const unsigned* range,
01331         const unsigned* otherCorner,
01332         ArrayND<Num2, Len2, Dim2>& r,
01333         Functor binaryFunct)
01334     {
01335         const unsigned imax = range[level];
01336         const unsigned leftShift = thisCorner[level];
01337         const unsigned leftPeriod = shape_[level];
01338         const unsigned rightShift = otherCorner[level];
01339         const unsigned rightPeriod = r.shape_[level];
01340 
01341         if (level == dim_ - 1)
01342         {
01343             Numeric* left = data_ + idx0;
01344             Num2* right = r.data_ + idx1;
01345             for (unsigned i=0; i<imax; ++i)
01346                 binaryFunct(left[(i+leftShift)%leftPeriod],
01347                             right[(i+rightShift)%rightPeriod]);
01348         }
01349         else
01350         {
01351             const unsigned long leftStride = strides_[level];
01352             const unsigned long rightStride = r.strides_[level];
01353             for (unsigned i=0; i<imax; ++i)
01354                 dualCircularLoop(
01355                     level+1, idx0+((i+leftShift)%leftPeriod)*leftStride,
01356                     idx1+((i+rightShift)%rightPeriod)*rightStride,
01357                     thisCorner, range, otherCorner, r, binaryFunct);
01358         }
01359     }
01360 
01361     template<typename Numeric, unsigned Len, unsigned Dim>
01362     template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
01363     void ArrayND<Numeric,Len,Dim>::flatCircularLoop(
01364         unsigned level, unsigned long idx0,
01365         unsigned long idx1,
01366         const unsigned* thisCorner,
01367         const unsigned* range,
01368         const unsigned* otherCorner,
01369         ArrayND<Num2, Len2, Dim2>& r,
01370         Functor binaryFunct)
01371     {
01372         const unsigned imax = range[level];
01373         const unsigned rightShift = otherCorner[level];
01374         const unsigned rightPeriod = r.shape_[level];
01375 
01376         if (level == dim_ - 1)
01377         {
01378             Numeric* left = data_ + (idx0 + thisCorner[level]);
01379             Numeric* const lMax = data_ + (idx0 + shape_[level]);
01380             Num2* right = r.data_ + idx1;
01381 
01382             for (unsigned i=0; i<imax && left<lMax; ++i)
01383                 binaryFunct(*left++, right[(i+rightShift)%rightPeriod]);
01384         }
01385         else
01386         {
01387             const unsigned long leftStride = strides_[level];
01388             const unsigned long leftMax = idx0 + shape_[level]*leftStride;
01389             idx0 += thisCorner[level]*leftStride;
01390             const unsigned long rightStride = r.strides_[level];
01391 
01392             for (unsigned i=0; i<imax && idx0 < leftMax; ++i, idx0+=leftStride)
01393                 flatCircularLoop(
01394                     level+1, idx0,
01395                     idx1+((i+rightShift)%rightPeriod)*rightStride,
01396                     thisCorner, range, otherCorner, r, binaryFunct);
01397         }
01398     }
01399 
01400     template<typename Numeric, unsigned Len, unsigned Dim>
01401     template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
01402     void ArrayND<Numeric,Len,Dim>::circularFlatLoop(
01403         unsigned level, unsigned long idx0,
01404         unsigned long idx1,
01405         const unsigned* thisCorner,
01406         const unsigned* range,
01407         const unsigned* otherCorner,
01408         ArrayND<Num2, Len2, Dim2>& r,
01409         Functor binaryFunct)
01410     {
01411         const unsigned imax = range[level];
01412         const unsigned leftShift = thisCorner[level];
01413         const unsigned leftPeriod = shape_[level];
01414 
01415         if (level == dim_ - 1)
01416         {
01417             Numeric* left = data_ + idx0;
01418             Num2* right = r.data_ + (idx1 + otherCorner[level]);
01419             Num2* const rMax = r.data_ + (idx1 + r.shape_[level]);
01420 
01421             for (unsigned i=0; i<imax && right<rMax; ++i)
01422                 binaryFunct(left[(i+leftShift)%leftPeriod], *right++);
01423         }
01424         else
01425         {
01426             const unsigned long leftStride = strides_[level];
01427             const unsigned long rightStride = r.strides_[level];
01428             const unsigned long rightMax = idx1 + r.shape_[level]*rightStride;
01429             idx1 += otherCorner[level]*rightStride;
01430 
01431             for (unsigned i=0; i<imax && idx1<rightMax; ++i, idx1+=rightStride)
01432                 circularFlatLoop(
01433                     level+1, idx0+((i+leftShift)%leftPeriod)*leftStride,
01434                     idx1, thisCorner, range, otherCorner, r, binaryFunct);
01435         }
01436     }
01437 
01438     me_macro_check_loop_prerequisites(jointSubrangeScan, commonSubrangeLoop)
01439     me_macro_check_loop_prerequisites(dualCircularScan, dualCircularLoop)
01440     me_macro_check_loop_prerequisites(flatCircularScan, flatCircularLoop)
01441     me_macro_check_loop_prerequisites(circularFlatScan, circularFlatLoop)
01442 
01443     template <typename Numeric, unsigned StackLen, unsigned StackDim>
01444     template <typename Num2, unsigned Len2, unsigned Dim2>
01445     Numeric ArrayND<Numeric,StackLen,StackDim>::marginalizeInnerLoop(
01446         unsigned long idx, const unsigned levelPr, unsigned long idxPr,
01447         const ArrayND<Num2,Len2,Dim2>& prior,
01448         const unsigned* indexMap) const
01449     {
01450         Numeric sum = Numeric();
01451         const unsigned long myStride = strides_[indexMap[levelPr]];
01452         const unsigned imax = prior.shape_[levelPr];
01453         assert(imax == shape_[indexMap[levelPr]]);
01454         if (levelPr == prior.dim_ - 1)
01455         {
01456             for (unsigned i=0; i<imax; ++i)
01457                 sum += data_[idx+i*myStride]*prior.data_[idxPr++];
01458         }
01459         else
01460         {
01461             const unsigned long priorStride = prior.strides_[levelPr];
01462             for (unsigned i=0; i<imax; ++i)
01463             {
01464                 sum += marginalizeInnerLoop(idx, levelPr+1U, idxPr,
01465                                             prior, indexMap);
01466                 idx += myStride;
01467                 idxPr += priorStride;
01468             }
01469         }
01470         return sum;
01471     }
01472 
01473     template <typename Numeric, unsigned StackLen, unsigned StackDim>
01474     template <typename Num2, unsigned Len2, unsigned Dim2>
01475     void ArrayND<Numeric,StackLen,StackDim>::marginalizeLoop(
01476         const unsigned level, unsigned long idx,
01477         const unsigned levelRes, unsigned long idxRes,
01478         const ArrayND<Num2,Len2,Dim2>& prior,
01479         const unsigned* indexMap, ArrayND& result) const
01480     {
01481         if (level == dim_)
01482         {
01483             const Numeric res = marginalizeInnerLoop(
01484                 idx, 0U, 0UL, prior, indexMap);
01485             if (result.dim_)
01486                 result.data_[idxRes] = res;
01487             else
01488                 result.localData_[0] = res;
01489         }
01490         else
01491         {
01492             // Check if this level is mapped or not
01493             bool mapped = false;
01494             for (unsigned i=0; i<prior.dim_; ++i)
01495                 if (level == indexMap[i])
01496                 {
01497                     mapped = true;
01498                     break;
01499                 }
01500             if (mapped)
01501                 marginalizeLoop(level+1U, idx, levelRes, idxRes,
01502                                 prior, indexMap, result);
01503             else
01504             {
01505                 const unsigned imax = shape_[level];
01506                 const unsigned long myStride = strides_[level];
01507                 const unsigned long resStride = result.strides_[levelRes];
01508                 for (unsigned i=0; i<imax; ++i)
01509                 {
01510                     marginalizeLoop(level+1U, idx, levelRes+1U, idxRes,
01511                                     prior, indexMap, result);
01512                     idx += myStride;
01513                     idxRes += resStride;
01514                 }
01515             }
01516         }
01517     }
01518 
01519     template<typename Numeric, unsigned StackLen, unsigned StackDim>
01520     template <typename Num2, unsigned Len2, unsigned Dim2>
01521     ArrayND<Numeric,StackLen,StackDim>
01522     ArrayND<Numeric,StackLen,StackDim>::marginalize(
01523         const ArrayND<Num2,Len2,Dim2>& prior,
01524         const unsigned* indexMap, const unsigned mapLen) const
01525     {
01526         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
01527             "Initialize npstat::ArrayND before calling method \"marginalize\"");
01528         if (!(prior.dim_ && prior.dim_ <= dim_)) throw npstat::NpstatInvalidArgument(
01529             "In npstat::ArrayND::marginalize: incompatible argument array rank");
01530         const unsigned resultDim = dim_ - prior.dim_;
01531 
01532         // Check that the index map is reasonable
01533         if (mapLen != prior.dim_) throw npstat::NpstatInvalidArgument(
01534             "In npstat::ArrayND::marginalize: incompatible index map length");
01535         assert(indexMap);
01536         for (unsigned i=0; i<mapLen; ++i)
01537         {
01538             const unsigned thisInd = indexMap[i];
01539             if (shape_[thisInd] != prior.shape_[i]) throw npstat::NpstatInvalidArgument(
01540                 "In npstat::ArrayND::marginalize: "
01541                 "incompatible argument array dimensions");
01542             if (thisInd >= dim_) throw npstat::NpstatOutOfRange(
01543                 "In npstat::ArrayND::marginalize: index map entry out of range");
01544             for (unsigned j=0; j<i; ++j)
01545                 if (indexMap[j] == thisInd) throw npstat::NpstatInvalidArgument(
01546                     "In npstat::ArrayND::marginalize: "
01547                     "duplicate entry in the index map");
01548         }
01549 
01550         // Build the shape for the array of results
01551         ArrayShape newShape;
01552         newShape.reserve(resultDim);
01553         for (unsigned i=0; i<dim_; ++i)
01554         {
01555             bool mapped = false;
01556             for (unsigned j=0; j<mapLen; ++j)
01557                 if (indexMap[j] == i)
01558                 {
01559                     mapped = true;
01560                     break;
01561                 }
01562             if (!mapped)
01563                 newShape.push_back(shape_[i]);
01564         }
01565 
01566         ArrayND result(newShape);
01567         assert(result.dim_ == resultDim);
01568         bool calculated = false;
01569         if (resultDim == 0)
01570         {
01571             calculated = true;
01572             for (unsigned i=0; i<dim_; ++i)
01573                 if (indexMap[i] != i)
01574                 {
01575                     calculated = false;
01576                     break;
01577                 }
01578             if (calculated)
01579             {
01580                 Numeric sum = Numeric();
01581                 for (unsigned long i=0; i<len_; ++i)
01582                     sum += data_[i]*prior.data_[i];
01583                 result.localData_[0] = sum;
01584             }
01585         }
01586 
01587         if (!calculated)
01588             marginalizeLoop(0U, 0UL, 0U, 0UL, prior, indexMap, result);
01589 
01590         return result;
01591     }
01592 
01593     template<typename Numeric, unsigned Len, unsigned Dim>
01594     void ArrayND<Numeric,Len,Dim>::buildFromShapePtr(
01595         const unsigned* sizes, const unsigned dim)
01596     {
01597         dim_ = dim;
01598         if (dim_)
01599         {
01600             assert(sizes);
01601             for (unsigned i=0; i<dim_; ++i)
01602                 if (sizes[i] == 0)
01603                     throw npstat::NpstatInvalidArgument(
01604                         "In npstat::ArrayND::buildFromShapePtr: "
01605                         "detected span of zero");
01606 
01607             // Copy the array shape and figure out the array length
01608             shape_ = makeBuffer(dim_, localShape_, Dim);
01609             for (unsigned i=0; i<dim_; ++i)
01610             {
01611                 shape_[i] = sizes[i];
01612                 len_ *= shape_[i];
01613             }
01614 
01615             // Figure out the array strides
01616             buildStrides();
01617 
01618             // Allocate the data array
01619             data_ = makeBuffer(len_, localData_, Len);
01620         }
01621         else
01622         {
01623             localData_[0] = Numeric();
01624             data_ = localData_;
01625         }
01626     }
01627 
01628     template<typename Numeric, unsigned StackLen, unsigned StackDim>
01629     template <typename Num2, unsigned Len2, unsigned Dim2>
01630     ArrayND<Numeric,StackLen,StackDim>::ArrayND(
01631         const ArrayND<Num2, Len2, Dim2>& slicedArray,
01632         const unsigned *fixedIndices, const unsigned nFixedIndices)
01633         : data_(0), strides_(0), shape_(0),
01634           len_(1UL), dim_(slicedArray.dim_ - nFixedIndices),
01635           shapeIsKnown_(true)
01636     {
01637         if (nFixedIndices)
01638         {
01639             assert(fixedIndices);
01640             if (nFixedIndices > slicedArray.dim_) throw npstat::NpstatInvalidArgument(
01641                 "In npstat::ArrayND slicing constructor: too many fixed indices");
01642             if (!slicedArray.shapeIsKnown_) throw npstat::NpstatInvalidArgument(
01643                 "In npstat::ArrayND slicing constructor: "
01644                 "uninitialized argument array");
01645 
01646             // Check that the fixed indices are within range
01647             for (unsigned j=0; j<nFixedIndices; ++j)
01648                 if (fixedIndices[j] >= slicedArray.dim_)
01649                     throw npstat::NpstatOutOfRange("In npstat::ArrayND slicing "
01650                         "constructor: fixed index out of range");
01651 
01652             // Build the shape for the slice
01653             shape_ = makeBuffer(dim_, localShape_, StackDim);
01654             unsigned idim = 0;
01655             for (unsigned i=0; i<slicedArray.dim_; ++i)
01656             {
01657                 bool fixed = false;
01658                 for (unsigned j=0; j<nFixedIndices; ++j)
01659                     if (fixedIndices[j] == i)
01660                     {
01661                         fixed = true;
01662                         break;
01663                     }
01664                 if (!fixed)
01665                 {
01666                     assert(idim < dim_);
01667                     shape_[idim++] = slicedArray.shape_[i];
01668                 }
01669             }
01670             assert(idim == dim_);
01671 
01672             if (dim_)
01673             {
01674                 // Copy the array shape and figure out the array length
01675                 for (unsigned i=0; i<dim_; ++i)
01676                     len_ *= shape_[i];
01677 
01678                 // Figure out the array strides
01679                 buildStrides();
01680 
01681                 // Allocate the data array
01682                 data_ = makeBuffer(len_, localData_, StackLen);
01683             }
01684             else
01685             {
01686                 localData_[0] = Numeric();
01687                 data_ = localData_;
01688             }
01689         }
01690         else
01691         {
01692             new (this) ArrayND(slicedArray);
01693         }
01694     }
01695 
01696     template<typename Numeric, unsigned StackLen, unsigned StackDim>
01697     template <typename Num2, unsigned Len2, unsigned Dim2>
01698     unsigned long ArrayND<Numeric,StackLen,StackDim>::verifySliceCompatibility(
01699         const ArrayND<Num2,Len2,Dim2>& slice,
01700         const unsigned *fixedIndices,
01701         const unsigned *fixedIndexValues,
01702         const unsigned nFixedIndices) const
01703     {
01704         if (!(nFixedIndices && nFixedIndices <= dim_))
01705             throw npstat::NpstatInvalidArgument(
01706                 "In npstat::ArrayND::verifySliceCompatibility: "
01707                 "invalid number of fixed indices");
01708         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
01709             "Initialize npstat::ArrayND before calling "
01710             "method \"verifySliceCompatibility\"");
01711         if (!slice.shapeIsKnown_) throw npstat::NpstatInvalidArgument(
01712             "In npstat::ArrayND::verifySliceCompatibility: "
01713             "uninitialized argument array");
01714         if (slice.dim_ != dim_ - nFixedIndices) throw npstat::NpstatInvalidArgument(
01715             "In npstat::ArrayND::verifySliceCompatibility: "
01716             "incompatible argument array rank");
01717         assert(fixedIndices);
01718         assert(fixedIndexValues);
01719 
01720         for (unsigned j=0; j<nFixedIndices; ++j)
01721             if (fixedIndices[j] >= dim_) throw npstat::NpstatOutOfRange(
01722                 "In npstat::ArrayND::verifySliceCompatibility: "
01723                 "fixed index out of range");
01724 
01725         // Check slice shape compatibility
01726         unsigned long idx = 0UL;
01727         unsigned sliceDim = 0U;
01728         for (unsigned i=0; i<dim_; ++i)
01729         {
01730             bool fixed = false;
01731             for (unsigned j=0; j<nFixedIndices; ++j)
01732                 if (fixedIndices[j] == i)
01733                 {
01734                     fixed = true;
01735                     if (fixedIndexValues[j] >= shape_[i])
01736                         throw npstat::NpstatOutOfRange(
01737                             "In npstat::ArrayND::verifySliceCompatibility: "
01738                             "fixed index value out of range");
01739                     idx += fixedIndexValues[j]*strides_[i];
01740                     break;
01741                 }
01742             if (!fixed)
01743             {
01744                 if (shape_[i] != slice.shape_[sliceDim])
01745                      throw npstat::NpstatInvalidArgument(
01746                          "In npstat::ArrayND::verifySliceCompatibility: "
01747                          "incompatible argument array dimensions");
01748                 ++sliceDim;
01749             }
01750         }       
01751         assert(sliceDim == slice.dim_);
01752         return idx;
01753     }
01754 
01755     template<typename Numeric, unsigned StackLen, unsigned StackDim>
01756     template <typename Num2, unsigned Len2, unsigned Dim2, class Op>
01757     void ArrayND<Numeric,StackLen,StackDim>::jointSliceLoop(
01758         const unsigned level, const unsigned long idx0,
01759         const unsigned level1, const unsigned long idx1,
01760         ArrayND<Num2,Len2,Dim2>& slice,
01761         const unsigned *fixedIndices,
01762         const unsigned *fixedIndexValues,
01763         const unsigned nFixedIndices,
01764         Op fcn)
01765     {
01766         bool fixed = false;
01767         for (unsigned j=0; j<nFixedIndices; ++j)
01768             if (fixedIndices[j] == level)
01769             {
01770                 fixed = true;
01771                 break;
01772             }
01773         if (fixed)
01774         {
01775             jointSliceLoop(level+1, idx0, level1, idx1,
01776                            slice, fixedIndices, fixedIndexValues,
01777                            nFixedIndices, fcn);
01778         }
01779         else
01780         {
01781             const unsigned imax = shape_[level];
01782             assert(imax == slice.shape_[level1]);
01783             const unsigned long stride = strides_[level];
01784 
01785             if (level1 == slice.dim_ - 1)
01786             {
01787                 Num2* to = slice.data_ + idx1;
01788                 for (unsigned i = 0; i<imax; ++i)
01789                     fcn(data_[idx0 + i*stride], to[i]);
01790             }
01791             else
01792             {
01793                 const unsigned long stride2 = slice.strides_[level1];
01794                 for (unsigned i = 0; i<imax; ++i)
01795                     jointSliceLoop(level+1, idx0+i*stride,
01796                                    level1+1, idx1+i*stride2,
01797                                    slice, fixedIndices, fixedIndexValues,
01798                                    nFixedIndices, fcn);
01799             }
01800         }
01801     }
01802 
01803     template<typename Numeric, unsigned StackLen, unsigned StackDim>
01804     template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
01805     void ArrayND<Numeric,StackLen,StackDim>::jointSliceScan(
01806         ArrayND<Num2,Len2,Dim2>& slice,
01807         const unsigned *fixedIndices,
01808         const unsigned *fixedIndexValues,
01809         const unsigned nFixedIndices,
01810         Functor binaryFunct)
01811     {
01812         const unsigned long idx = verifySliceCompatibility(
01813             slice, fixedIndices, fixedIndexValues, nFixedIndices);
01814         if (slice.dim_)
01815             jointSliceLoop(0U, idx, 0U, 0UL, slice, fixedIndices,
01816                            fixedIndexValues, nFixedIndices, binaryFunct);
01817         else
01818             binaryFunct(data_[idx], slice.localData_[0]);
01819     }
01820 
01821     template<typename Numeric, unsigned StackLen, unsigned StackDim>
01822     template <typename Num2>
01823     void ArrayND<Numeric,StackLen,StackDim>::projectInnerLoop(
01824         const unsigned level, unsigned long idx0,
01825         unsigned* currentIndex,
01826         AbsArrayProjector<Numeric,Num2>& projector,
01827         const unsigned *projectedIndices,
01828         const unsigned nProjectedIndices) const
01829     {
01830         // level :  dimension number among indices which are being iterated
01831         const unsigned idx = projectedIndices[level];
01832         const unsigned imax = shape_[idx];
01833         const unsigned long stride = strides_[idx];
01834         const bool last = (level == nProjectedIndices - 1);
01835 
01836         for (unsigned i = 0; i<imax; ++i)
01837         {
01838             currentIndex[idx] = i;
01839             if (last)
01840                 projector.process(currentIndex, dim_, idx0, data_[idx0]);
01841             else
01842                 projectInnerLoop(level+1, idx0, currentIndex, projector, 
01843                                  projectedIndices, nProjectedIndices);
01844             idx0 += stride;
01845         }
01846     }
01847 
01848     template<typename Numeric, unsigned StackLen, unsigned StackDim>
01849     template <typename Num2, unsigned Len2, unsigned Dim2,
01850               typename Num3, class Op>
01851     void ArrayND<Numeric,StackLen,StackDim>::projectLoop(
01852         const unsigned level, const unsigned long idx0,
01853         const unsigned level1, const unsigned long idx1,
01854         unsigned* currentIndex,
01855         ArrayND<Num2,Len2,Dim2>* projection,
01856         AbsArrayProjector<Numeric,Num3>& projector,
01857         const unsigned *projectedIndices,
01858         const unsigned nProjectedIndices, Op fcn) const
01859     {
01860         // level        : dimension number in this array
01861         // level1       : dimension number in the projection
01862         // idx0         : linear index in this array
01863         // idx1         : linear index in the projection
01864         // currentIndex : cycled over in this loop with the exception of the
01865         //                dimensions which are iterated over to build the
01866         //                projection
01867         if (level == dim_)
01868         {
01869             assert(level1 == projection->dim_);
01870             projector.clear();
01871             projectInnerLoop(0U, idx0, currentIndex, projector,
01872                              projectedIndices, nProjectedIndices);
01873             if (projection->dim_)
01874                 fcn(projection->data_[idx1], projector.result());
01875             else
01876                 fcn(projection->localData_[0], projector.result());
01877         }
01878         else
01879         {
01880             bool iterated = false;
01881             for (unsigned j=0; j<nProjectedIndices; ++j)
01882                 if (projectedIndices[j] == level)
01883                 {
01884                     iterated = true;
01885                     break;
01886                 }
01887             if (iterated)
01888             {
01889                 // This index will be iterated over inside "projectInnerLoop"
01890                 projectLoop(level+1, idx0, level1, idx1,
01891                             currentIndex, projection, projector,
01892                             projectedIndices, nProjectedIndices, fcn);
01893             }
01894             else
01895             {
01896                 const unsigned imax = shape_[level];
01897                 const unsigned long stride = strides_[level];
01898                 // We will not be able to get here if projection->dim_ is 0.
01899                 // Therefore, it is safe to access projection->strides_.
01900                 const unsigned long stride2 = projection->strides_[level1];
01901                 for (unsigned i = 0; i<imax; ++i)
01902                 {
01903                     currentIndex[level] = i;
01904                     projectLoop(level+1, idx0+i*stride,
01905                                 level1+1, idx1+i*stride2,
01906                                 currentIndex, projection, projector,
01907                                 projectedIndices, nProjectedIndices, fcn);
01908                 }
01909             }
01910         }
01911     }
01912 
01913     template<typename Numeric, unsigned StackLen, unsigned StackDim>
01914     template <typename Num2, unsigned Len2, unsigned Dim2>
01915     void ArrayND<Numeric,StackLen,StackDim>::verifyProjectionCompatibility(
01916         const ArrayND<Num2,Len2,Dim2>& projection,
01917         const unsigned *projectedIndices,
01918         const unsigned nProjectedIndices) const
01919     {
01920         if (!(nProjectedIndices && nProjectedIndices <= dim_))
01921             throw npstat::NpstatInvalidArgument(
01922                 "In npstat::ArrayND::verifyProjectionCompatibility: "
01923                 "invalid number of projected indices");
01924         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
01925             "Initialize npstat::ArrayND before calling "
01926             "method \"verifyProjectionCompatibility\"");
01927         if (!projection.shapeIsKnown_) throw npstat::NpstatInvalidArgument(
01928             "In npstat::ArrayND::verifyProjectionCompatibility: "
01929             "uninitialized argument array");
01930         if (projection.dim_ != dim_ - nProjectedIndices)
01931             throw npstat::NpstatInvalidArgument(
01932                 "In npstat::ArrayND::verifyProjectionCompatibility: "
01933                 "incompatible argument array rank");
01934         assert(projectedIndices);
01935 
01936         for (unsigned j=0; j<nProjectedIndices; ++j)
01937             if (projectedIndices[j] >= dim_) throw npstat::NpstatOutOfRange(
01938                 "In npstat::ArrayND::verifyProjectionCompatibility: "
01939                 "projected index out of range");
01940 
01941         // Check projection shape compatibility
01942         unsigned sliceDim = 0U;
01943         for (unsigned i=0; i<dim_; ++i)
01944         {
01945             bool fixed = false;
01946             for (unsigned j=0; j<nProjectedIndices; ++j)
01947                 if (projectedIndices[j] == i)
01948                 {
01949                     fixed = true;
01950                     break;
01951                 }
01952             if (!fixed)
01953             {
01954                 if (shape_[i] != projection.shape_[sliceDim])
01955                      throw npstat::NpstatInvalidArgument(
01956                          "In npstat::ArrayND::verifyProjectionCompatibility: "
01957                          "incompatible argument array dimensions");
01958                 ++sliceDim;
01959             }
01960         }
01961         assert(sliceDim == projection.dim_);
01962     }
01963 
01964     template<typename Numeric, unsigned StackLen, unsigned StackDim>
01965     template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
01966     void ArrayND<Numeric,StackLen,StackDim>::project(
01967         ArrayND<Num2,Len2,Dim2>* projection,
01968         AbsArrayProjector<Numeric,Num3>& projector,
01969         const unsigned *projectedIndices,
01970         const unsigned nProjectedIndices) const
01971     {
01972         assert(projection);
01973         verifyProjectionCompatibility(*projection, projectedIndices,
01974                                       nProjectedIndices);
01975         unsigned ibuf[StackDim];
01976         unsigned* buf = makeBuffer(dim_, ibuf, StackDim);
01977         for (unsigned i=0; i<dim_; ++i)
01978             buf[i] = 0U;
01979         projectLoop(0U, 0UL, 0U, 0UL, buf, projection,
01980                     projector, projectedIndices, nProjectedIndices,
01981                     scast_assign_left<Num2,Num3>());
01982         destroyBuffer(buf, ibuf);
01983     }
01984 
01985     template<typename Numeric, unsigned StackLen, unsigned StackDim>
01986     template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
01987     void ArrayND<Numeric,StackLen,StackDim>::addToProjection(
01988         ArrayND<Num2,Len2,Dim2>* projection,
01989         AbsArrayProjector<Numeric,Num3>& projector,
01990         const unsigned *projectedIndices,
01991         const unsigned nProjectedIndices) const
01992     {
01993         assert(projection);
01994         verifyProjectionCompatibility(*projection, projectedIndices,
01995                                       nProjectedIndices);
01996         unsigned ibuf[StackDim];
01997         unsigned* buf = makeBuffer(dim_, ibuf, StackDim);
01998         for (unsigned i=0; i<dim_; ++i)
01999             buf[i] = 0U;
02000         projectLoop(0U, 0UL, 0U, 0UL, buf, projection,
02001                     projector, projectedIndices, nProjectedIndices,
02002                     scast_pluseq_left<Num2,Num3>());        
02003         destroyBuffer(buf, ibuf);
02004     }
02005 
02006     template<typename Numeric, unsigned StackLen, unsigned StackDim>
02007     template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
02008     void ArrayND<Numeric,StackLen,StackDim>::subtractFromProjection(
02009         ArrayND<Num2,Len2,Dim2>* projection,
02010         AbsArrayProjector<Numeric,Num3>& projector,
02011         const unsigned *projectedIndices,
02012         const unsigned nProjectedIndices) const
02013     {
02014         assert(projection);
02015         verifyProjectionCompatibility(*projection, projectedIndices,
02016                                       nProjectedIndices);
02017         unsigned ibuf[StackDim];
02018         unsigned* buf = makeBuffer(dim_, ibuf, StackDim);
02019         for (unsigned i=0; i<dim_; ++i)
02020             buf[i] = 0U;
02021         projectLoop(0U, 0UL, 0U, 0UL, buf, projection,
02022                     projector, projectedIndices, nProjectedIndices,
02023                     scast_minuseq_left<Num2,Num3>());        
02024         destroyBuffer(buf, ibuf);
02025     }
02026 
02027     template<typename Numeric, unsigned StackLen, unsigned StackDim>
02028     template <typename Num2>
02029     void ArrayND<Numeric,StackLen,StackDim>::projectInnerLoop2(
02030         const unsigned level, const unsigned long idx0,
02031         AbsVisitor<Numeric,Num2>& projector,
02032         const unsigned *projectedIndices,
02033         const unsigned nProjectedIndices) const
02034     {
02035         const unsigned idx = projectedIndices[level];
02036         const unsigned imax = shape_[idx];
02037         const unsigned long stride = strides_[idx];
02038         const bool last = (level == nProjectedIndices - 1);
02039 
02040         for (unsigned i = 0; i<imax; ++i)
02041         {
02042             if (last)
02043                 projector.process(data_[idx0+i*stride]);
02044             else
02045                 projectInnerLoop2(level+1, idx0+i*stride, projector, 
02046                                   projectedIndices, nProjectedIndices);
02047         }
02048     }
02049 
02050     template<typename Numeric, unsigned StackLen, unsigned StackDim>
02051     template <typename Num2, unsigned Len2, unsigned Dim2,
02052               typename Num3, class Op>
02053     void ArrayND<Numeric,StackLen,StackDim>::projectLoop2(
02054         const unsigned level, const unsigned long idx0,
02055         const unsigned level1, const unsigned long idx1,
02056         ArrayND<Num2,Len2,Dim2>* projection,
02057         AbsVisitor<Numeric,Num3>& projector,
02058         const unsigned *projectedIndices,
02059         const unsigned nProjectedIndices, Op fcn) const
02060     {
02061         if (level == dim_)
02062         {
02063             assert(level1 == projection->dim_);
02064             projector.clear();
02065             projectInnerLoop2(0U, idx0, projector,
02066                               projectedIndices, nProjectedIndices);
02067             if (projection->dim_)
02068                 fcn(projection->data_[idx1], projector.result());
02069             else
02070                 fcn(projection->localData_[0], projector.result());
02071         }
02072         else
02073         {
02074             bool fixed = false;
02075             for (unsigned j=0; j<nProjectedIndices; ++j)
02076                 if (projectedIndices[j] == level)
02077                 {
02078                     fixed = true;
02079                     break;
02080                 }
02081             if (fixed)
02082             {
02083                 projectLoop2(level+1, idx0, level1, idx1,
02084                              projection, projector,
02085                              projectedIndices, nProjectedIndices, fcn);
02086             }
02087             else
02088             {
02089                 const unsigned imax = shape_[level];
02090                 const unsigned long stride = strides_[level];
02091                 const unsigned long stride2 = projection->strides_[level1];
02092                 for (unsigned i = 0; i<imax; ++i)
02093                     projectLoop2(level+1, idx0+i*stride,
02094                                  level1+1, idx1+i*stride2,
02095                                  projection, projector,
02096                                  projectedIndices, nProjectedIndices, fcn);
02097             }
02098         }
02099     }
02100 
02101     template<typename Numeric, unsigned StackLen, unsigned StackDim>
02102     template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
02103     void ArrayND<Numeric,StackLen,StackDim>::project(
02104         ArrayND<Num2,Len2,Dim2>* projection,
02105         AbsVisitor<Numeric,Num3>& projector,
02106         const unsigned *projectedIndices,
02107         const unsigned nProjectedIndices) const
02108     {
02109         assert(projection);
02110         verifyProjectionCompatibility(*projection, projectedIndices,
02111                                       nProjectedIndices);
02112         projectLoop2(0U, 0UL, 0U, 0UL, projection,
02113                      projector, projectedIndices, nProjectedIndices,
02114                      scast_assign_left<Num2,Num3>());
02115     }
02116 
02117     template<typename Numeric, unsigned StackLen, unsigned StackDim>
02118     template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
02119     void ArrayND<Numeric,StackLen,StackDim>::addToProjection(
02120         ArrayND<Num2,Len2,Dim2>* projection,
02121         AbsVisitor<Numeric,Num3>& projector,
02122         const unsigned *projectedIndices,
02123         const unsigned nProjectedIndices) const
02124     {
02125         assert(projection);
02126         verifyProjectionCompatibility(*projection, projectedIndices,
02127                                       nProjectedIndices);
02128         projectLoop2(0U, 0UL, 0U, 0UL, projection,
02129                      projector, projectedIndices, nProjectedIndices,
02130                      scast_pluseq_left<Num2,Num3>());
02131     }
02132 
02133     template<typename Numeric, unsigned StackLen, unsigned StackDim>
02134     template <typename Num2, unsigned Len2, unsigned Dim2, typename Num3>
02135     void ArrayND<Numeric,StackLen,StackDim>::subtractFromProjection(
02136         ArrayND<Num2,Len2,Dim2>* projection,
02137         AbsVisitor<Numeric,Num3>& projector,
02138         const unsigned *projectedIndices,
02139         const unsigned nProjectedIndices) const
02140     {
02141         assert(projection);
02142         verifyProjectionCompatibility(*projection, projectedIndices,
02143                                       nProjectedIndices);
02144         projectLoop2(0U, 0UL, 0U, 0UL, projection,
02145                      projector, projectedIndices, nProjectedIndices,
02146                      scast_minuseq_left<Num2,Num3>());
02147     }
02148 
02149     template<typename Numeric, unsigned StackLen, unsigned StackDim>
02150     template <typename Num2, class Functor>
02151     void ArrayND<Numeric,StackLen,StackDim>::scaleBySliceInnerLoop(
02152         const unsigned level, const unsigned long idx0,
02153         Num2& scale, const unsigned *projectedIndices,
02154         const unsigned nProjectedIndices, Functor binaryFunct)
02155     {
02156         const unsigned idx = projectedIndices[level];
02157         const unsigned imax = shape_[idx];
02158         const unsigned long stride = strides_[idx];
02159 
02160         if (level == nProjectedIndices - 1)
02161         {
02162             Numeric* data = data_ + idx0;
02163             for (unsigned i = 0; i<imax; ++i)
02164                 binaryFunct(data[i*stride], scale);
02165         }
02166         else
02167             for (unsigned i = 0; i<imax; ++i)
02168                 scaleBySliceInnerLoop(level+1, idx0+i*stride, scale,
02169                                       projectedIndices, nProjectedIndices,
02170                                       binaryFunct);
02171     }
02172 
02173     template<typename Numeric, unsigned StackLen, unsigned StackDim>
02174     template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
02175     void ArrayND<Numeric,StackLen,StackDim>::scaleBySliceLoop(
02176         unsigned level, unsigned long idx0,
02177         unsigned level1, unsigned long idx1,
02178         ArrayND<Num2,Len2,Dim2>& slice,
02179         const unsigned *projectedIndices,
02180         const unsigned nProjectedIndices,
02181         Functor binaryFunct)
02182     {
02183         if (level == dim_)
02184         {
02185             assert(level1 == slice.dim_);
02186             Num2& scaleFactor = slice.dim_ ? slice.data_[idx1] : 
02187                                              slice.localData_[0];
02188             scaleBySliceInnerLoop(0U, idx0, scaleFactor, projectedIndices,
02189                                   nProjectedIndices, binaryFunct);
02190         }
02191         else
02192         {
02193             bool fixed = false;
02194             for (unsigned j=0; j<nProjectedIndices; ++j)
02195                 if (projectedIndices[j] == level)
02196                 {
02197                     fixed = true;
02198                     break;
02199                 }
02200             if (fixed)
02201             {
02202                 scaleBySliceLoop(level+1, idx0, level1, idx1, slice,
02203                                  projectedIndices, nProjectedIndices,
02204                                  binaryFunct);
02205             }
02206             else
02207             {
02208                 const unsigned imax = shape_[level];
02209                 const unsigned long stride = strides_[level];
02210                 const unsigned long stride2 = slice.strides_[level1];
02211                 for (unsigned i = 0; i<imax; ++i)
02212                     scaleBySliceLoop(level+1, idx0+i*stride, level1+1,
02213                                      idx1+i*stride2, slice, projectedIndices,
02214                                      nProjectedIndices, binaryFunct);
02215             }
02216         }
02217     }
02218 
02219     template<typename Numeric, unsigned StackLen, unsigned StackDim>
02220     template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
02221     void ArrayND<Numeric,StackLen,StackDim>::jointScan(
02222         ArrayND<Num2, Len2, Dim2>& r, Functor binaryFunct)
02223     {
02224         if (!isShapeCompatible(r)) throw npstat::NpstatInvalidArgument(
02225             "In npstat::ArrayND::jointScan: incompatible argument array shape");
02226         if (dim_)
02227             for (unsigned long i=0; i<len_; ++i)
02228                 binaryFunct(data_[i], r.data_[i]);
02229         else
02230             binaryFunct(localData_[0], r.localData_[0]);
02231     }
02232 
02233     template<typename Numeric, unsigned StackLen, unsigned StackDim>
02234     template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
02235     void ArrayND<Numeric,StackLen,StackDim>::applySlice(
02236         ArrayND<Num2,Len2,Dim2>& slice,
02237         const unsigned *fixedIndices, const unsigned nFixedIndices,
02238         Functor binaryFunct)
02239     {
02240         if (nFixedIndices)
02241         {
02242             verifyProjectionCompatibility(slice, fixedIndices, nFixedIndices);
02243             if (slice.dim_ == 0U)
02244                 for (unsigned long i=0; i<len_; ++i)
02245                     binaryFunct(data_[i], slice.localData_[0]);
02246             else
02247                 scaleBySliceLoop(0U, 0UL, 0U, 0UL, slice,
02248                                  fixedIndices, nFixedIndices, binaryFunct);
02249         }
02250         else
02251             jointScan(slice, binaryFunct);
02252     }
02253 
02254     template<typename Numeric, unsigned StackLen, unsigned StackDim>
02255     inline bool ArrayND<Numeric,StackLen,StackDim>::isCompatible(
02256         const ArrayShape& shape) const
02257     {
02258         if (!shapeIsKnown_)
02259             return false;
02260         if (dim_ != shape.size())
02261             return false;
02262         if (dim_)
02263         {
02264             for (unsigned i=0; i<dim_; ++i)
02265                 if (shape_[i] != shape[i])
02266                     return false;
02267         }
02268         else
02269             assert(len_ == 1UL);
02270         return true;
02271     }
02272 
02273     template<typename Numeric, unsigned StackLen, unsigned StackDim>
02274     template <typename Num2, unsigned Len2, unsigned Dim2>
02275     inline bool ArrayND<Numeric,StackLen,StackDim>::isShapeCompatible(
02276         const ArrayND<Num2,Len2,Dim2>& r) const
02277     {
02278         if (!shapeIsKnown_)
02279             return false;
02280         if (!r.shapeIsKnown_)
02281             return false;
02282         if (dim_ != r.dim_)
02283             return false;
02284         if (len_ != r.len_)
02285             return false;
02286         if (dim_)
02287         {
02288             assert(shape_);
02289             assert(r.shape_);
02290             for (unsigned i=0; i<dim_; ++i)
02291                 if (shape_[i] != r.shape_[i])
02292                     return false;
02293         }
02294         else
02295             assert(len_ == 1UL);
02296         return true;
02297     }
02298 
02299     template<typename Numeric, unsigned Len, unsigned Dim>
02300     template<typename Num2, typename Integer>
02301     void ArrayND<Numeric,Len,Dim>::processSubrangeLoop(
02302         const unsigned level, unsigned long idx0,
02303         unsigned* currentIndex,
02304         AbsArrayProjector<Numeric,Num2>& f,
02305         const BoxND<Integer>& subrange) const
02306     {
02307         // Deal with possible negative limits first
02308         const Interval<Integer>& levelRange(subrange[level]);
02309         long long int iminl = static_cast<long long int>(levelRange.min());
02310         if (iminl < 0LL) iminl = 0LL;
02311         long long int imaxl = static_cast<long long int>(levelRange.max());
02312         if (imaxl < 0LL) imaxl = 0LL;
02313 
02314         // Now deal with possible out-of-range limits
02315         const unsigned imin = static_cast<unsigned>(iminl);
02316         unsigned imax = static_cast<unsigned>(imaxl);
02317         if (imax > shape_[level])
02318             imax = shape_[level];
02319 
02320         if (level == dim_ - 1)
02321         {
02322             idx0 += imin;
02323             for (unsigned i=imin; i<imax; ++i, ++idx0)
02324             {
02325                 currentIndex[level] = i;
02326                 f.process(currentIndex, dim_, idx0, data_[idx0]);
02327             }
02328         }
02329         else
02330         {
02331             const unsigned long stride = strides_[level];
02332             idx0 += imin*stride;
02333             for (unsigned i=imin; i<imax; ++i)
02334             {
02335                 currentIndex[level] = i;
02336                 processSubrangeLoop(level+1U, idx0, currentIndex, f, subrange);
02337                 idx0 += stride;
02338             }
02339         }
02340     }
02341 
02342     template<typename Numeric, unsigned Len, unsigned StackDim>
02343     template <typename Num2, typename Integer>
02344     void ArrayND<Numeric,Len,StackDim>::processSubrange(
02345         AbsArrayProjector<Numeric,Num2>& f,
02346         const BoxND<Integer>& subrange) const
02347     {
02348         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
02349             "Initialize npstat::ArrayND before calling method \"processSubrange\"");
02350         if (!dim_) throw npstat::NpstatInvalidArgument(
02351             "npstat::ArrayND::processSubrange method "
02352             "can not be used with array of 0 rank");
02353         if (dim_ != subrange.dim()) throw npstat::NpstatInvalidArgument(
02354             "In npstat::ArrayND::processSubrange: incompatible subrange rank");
02355         unsigned ibuf[StackDim];
02356         unsigned* buf = makeBuffer(dim_, ibuf, StackDim);
02357         for (unsigned i=0; i<dim_; ++i)
02358             buf[i] = 0U;
02359         processSubrangeLoop(0U, 0UL, buf, f, subrange);
02360         destroyBuffer(buf, ibuf);
02361     }
02362 
02363     template<typename Numeric, unsigned Len, unsigned Dim>
02364     template<typename Num2>
02365     inline ArrayND<Numeric,Len,Dim>& ArrayND<Numeric,Len,Dim>::setData(
02366         const Num2* data, const unsigned long dataLength)
02367     {
02368         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
02369             "Initialize npstat::ArrayND before calling method \"setData\"");
02370         if (dataLength != len_) throw npstat::NpstatInvalidArgument(
02371             "In npstat::ArrayND::setData: incompatible input data length");
02372         copyBuffer(data_, data, dataLength);
02373         return *this;
02374     }
02375 
02376     template<typename Numeric, unsigned Len, unsigned Dim>
02377     void ArrayND<Numeric,Len,Dim>::buildStrides()
02378     {
02379         assert(dim_);
02380         if (strides_ == 0)
02381             strides_ = makeBuffer(dim_, localStrides_, Dim);
02382         strides_[dim_ - 1] = 1UL;
02383         for (unsigned j=dim_ - 1; j>0; --j)
02384             strides_[j - 1] = strides_[j]*shape_[j];
02385     }
02386 
02387     template<typename Numeric, unsigned StackLen, unsigned StackDim>
02388     inline ArrayND<Numeric,StackLen,StackDim>::ArrayND()
02389         : data_(0), strides_(0), shape_(0),
02390           len_(0UL), dim_(0U), shapeIsKnown_(false)
02391     {
02392         localData_[0] = Numeric();
02393         data_ = localData_;
02394     }
02395 
02396     template<typename Numeric, unsigned Len, unsigned Dim>
02397     ArrayND<Numeric,Len,Dim>::ArrayND(const ArrayND& r)
02398         : data_(0), strides_(0), shape_(0),
02399           len_(r.len_), dim_(r.dim_), shapeIsKnown_(r.shapeIsKnown_)
02400     {
02401         if (dim_)
02402         {
02403             // Copy the shape
02404             shape_ = makeBuffer(dim_, localShape_, Dim);
02405             copyBuffer(shape_, r.shape_, dim_);
02406 
02407             // Copy the strides
02408             strides_ = makeBuffer(dim_, localStrides_, Dim);
02409             copyBuffer(strides_, r.strides_, dim_);
02410 
02411             // Copy the data
02412             data_ = makeBuffer(len_, localData_, Len);
02413             copyBuffer(data_, r.data_, len_);
02414         }
02415         else
02416         {
02417             assert(len_ == 1UL);
02418             localData_[0] = r.localData_[0];
02419             data_ = localData_;
02420         }
02421     }
02422 
02423     template<typename Numeric, unsigned Len, unsigned Dim>
02424     template <typename Num2, unsigned Len2, unsigned Dim2>
02425     ArrayND<Numeric,Len,Dim>::ArrayND(const ArrayND<Num2, Len2, Dim2>& r)
02426         : data_(0), strides_(0), shape_(0),
02427           len_(r.len_), dim_(r.dim_), shapeIsKnown_(r.shapeIsKnown_)
02428     {
02429         if (dim_)
02430         {
02431             // Copy the shape
02432             shape_ = makeBuffer(dim_, localShape_, Dim);
02433             copyBuffer(shape_, r.shape_, dim_);
02434 
02435             // Copy the strides
02436             strides_ = makeBuffer(dim_, localStrides_, Dim);
02437             copyBuffer(strides_, r.strides_, dim_);
02438 
02439             // Copy the data
02440             data_ = makeBuffer(len_, localData_, Len);
02441             copyBuffer(data_, r.data_, len_);
02442         }
02443         else
02444         {
02445             assert(len_ == 1UL);
02446             localData_[0] = static_cast<Numeric>(r.localData_[0]);
02447             data_ = localData_;
02448         }
02449     }
02450 
02451     template<typename Numeric, unsigned Len, unsigned Dim>
02452     template<typename Num2, unsigned Len2, unsigned Dim2, class Functor>
02453     ArrayND<Numeric,Len,Dim>::ArrayND(const ArrayND<Num2, Len2, Dim2>& r,
02454                                       Functor f)
02455         : data_(0), strides_(0), shape_(0),
02456           len_(r.len_), dim_(r.dim_), shapeIsKnown_(r.shapeIsKnown_)
02457     {
02458         if (dim_)
02459         {
02460             // Copy the shape
02461             shape_ = makeBuffer(dim_, localShape_, Dim);
02462             copyBuffer(shape_, r.shape_, dim_);
02463 
02464             // Copy the strides
02465             strides_ = makeBuffer(dim_, localStrides_, Dim);
02466             copyBuffer(strides_, r.strides_, dim_);
02467 
02468             // Copy the data
02469             data_ = makeBuffer(len_, localData_, Len);
02470             for (unsigned long i=0; i<len_; ++i)
02471                 data_[i] = static_cast<Numeric>(f(r.data_[i]));
02472         }
02473         else
02474         {
02475             assert(len_ == 1UL);
02476             localData_[0] = static_cast<Numeric>(f(r.localData_[0]));
02477             data_ = localData_;
02478         }
02479     }
02480 
02481     template<typename Numeric, unsigned Len, unsigned Dim>
02482     template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
02483     void ArrayND<Numeric,Len,Dim>::copyRangeLoopFunct(
02484         const unsigned level, unsigned long idx0,
02485         unsigned long idx1,
02486         const ArrayND<Num2, Len2, Dim2>& r,
02487         const ArrayRange& range, Functor f)
02488     {
02489         const unsigned imax = shape_[level];
02490         if (level == dim_ - 1)
02491         {
02492             Numeric* to = data_ + idx0;
02493             const Num2* from = r.data_ + (idx1 + range[level].min());
02494             for (unsigned i=0; i<imax; ++i)
02495                 *to++ = static_cast<Numeric>(f(*from++));
02496         }
02497         else
02498         {
02499             const unsigned long fromstride = r.strides_[level];
02500             const unsigned long tostride = strides_[level];
02501             idx1 += range[level].min()*fromstride;
02502             for (unsigned i=0; i<imax; ++i)
02503             {
02504                 copyRangeLoopFunct(level+1, idx0, idx1, r, range, f);
02505                 idx0 += tostride;
02506                 idx1 += fromstride;
02507             }
02508         }
02509     }
02510 
02511     template<typename Numeric, unsigned Len, unsigned Dim>
02512     template <typename Num2, unsigned Len2, unsigned Dim2>
02513     ArrayND<Numeric,Len,Dim>::ArrayND(
02514         const ArrayND<Num2, Len2, Dim2>& r, const ArrayRange& range)
02515         : data_(0), strides_(0), shape_(0),
02516           len_(r.len_), dim_(r.dim_), shapeIsKnown_(r.shapeIsKnown_)
02517     {
02518         if (!range.isCompatible(r.shape_, r.dim_))
02519             throw npstat::NpstatInvalidArgument(
02520                 "In npstat::ArrayND subrange constructor: invalid subrange");
02521         if (dim_)
02522         {
02523             len_ = range.rangeSize();
02524             if (!len_)
02525                 throw npstat::NpstatInvalidArgument(
02526                     "In npstat::ArrayND subrange constructor: empty subrange");
02527 
02528             // Figure out the shape
02529             shape_ = makeBuffer(dim_, localShape_, Dim);
02530             range.rangeLength(shape_, dim_);
02531 
02532             // Figure out the strides
02533             buildStrides();
02534 
02535             // Allocate the data array
02536             data_ = makeBuffer(len_, localData_, Len);
02537 
02538             // Copy the data
02539             if (dim_ > CHAR_BIT*sizeof(unsigned long))
02540                 throw npstat::NpstatInvalidArgument(
02541                     "In npstat::ArrayND subrange constructor: "
02542                     "input array rank is too large");
02543             unsigned lolim[CHAR_BIT*sizeof(unsigned long)];
02544             range.lowerLimits(lolim, dim_);
02545             unsigned toBuf[CHAR_BIT*sizeof(unsigned long)];
02546             clearBuffer(toBuf, dim_);
02547             (const_cast<ArrayND<Num2, Len2, Dim2>&>(r)).commonSubrangeLoop(
02548                 0U, 0UL, 0UL, lolim, shape_, toBuf, *this,
02549                 scast_assign_right<Num2,Numeric>());
02550         }
02551         else
02552         {
02553             assert(len_ == 1UL);
02554             localData_[0] = static_cast<Numeric>(r.localData_[0]);
02555             data_ = localData_;
02556         }
02557     }
02558 
02559     template<typename Numeric, unsigned Len, unsigned Dim>
02560     template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
02561     ArrayND<Numeric,Len,Dim>::ArrayND(
02562         const ArrayND<Num2, Len2, Dim2>& r, const ArrayRange& range,
02563         Functor f)
02564         : data_(0), strides_(0), shape_(0),
02565           len_(r.len_), dim_(r.dim_), shapeIsKnown_(r.shapeIsKnown_)
02566     {
02567         if (!range.isCompatible(r.shape_, r.dim_))
02568             throw npstat::NpstatInvalidArgument(
02569                 "In npstat::ArrayND transforming subrange constructor: "
02570                 "incompatible subrange");
02571         if (dim_)
02572         {
02573             len_ = range.rangeSize();
02574             if (!len_)
02575                 throw npstat::NpstatInvalidArgument(
02576                     "In npstat::ArrayND transforming subrange constructor: "
02577                     "empty subrange");
02578 
02579             // Figure out the shape
02580             shape_ = makeBuffer(dim_, localShape_, Dim);
02581             for (unsigned i=0; i<dim_; ++i)
02582                 shape_[i] = range[i].length();
02583 
02584             // Figure out the strides
02585             buildStrides();
02586 
02587             // Allocate the data array
02588             data_ = makeBuffer(len_, localData_, Len);
02589 
02590             // Transform the data
02591             copyRangeLoopFunct(0U, 0UL, 0UL, r, range, f);
02592         }
02593         else
02594         {
02595             assert(len_ == 1UL);
02596             localData_[0] = static_cast<Numeric>(f(r.localData_[0]));
02597             data_ = localData_;
02598         }
02599     }
02600 
02601     template<typename Numeric, unsigned Len, unsigned Dim>
02602     ArrayND<Numeric,Len,Dim>::ArrayND(const ArrayShape& sh)
02603         : data_(0), strides_(0), shape_(0), len_(1UL), shapeIsKnown_(true)
02604     {
02605         const unsigned sz = sh.size();
02606         buildFromShapePtr(sz ? &sh[0] : 0, sz);
02607     }
02608 
02609     template<typename Numeric, unsigned Len, unsigned Dim>
02610     ArrayND<Numeric,Len,Dim>::ArrayND(const unsigned* sizes,
02611                                       const unsigned dim)
02612         : data_(0), strides_(0), shape_(0), len_(1UL), shapeIsKnown_(true)
02613     {
02614         buildFromShapePtr(sizes, dim);
02615     }
02616 
02617     template<typename Numeric, unsigned Len, unsigned Dim>
02618     ArrayND<Numeric,Len,Dim>::ArrayND(const unsigned n0)
02619         : data_(0), strides_(0), shape_(0), len_(1UL), shapeIsKnown_(true)
02620     {
02621         const unsigned dim = 1U;
02622         unsigned sizes[dim];
02623         sizes[0] = n0;
02624         buildFromShapePtr(sizes, dim);
02625     }
02626 
02627     template<typename Numeric, unsigned Len, unsigned Dim>
02628     ArrayND<Numeric,Len,Dim>::ArrayND(const unsigned n0,
02629                                       const unsigned n1)
02630         : data_(0), strides_(0), shape_(0), len_(1UL), shapeIsKnown_(true)
02631     {
02632         const unsigned dim = 2U;
02633         unsigned sizes[dim];
02634         sizes[0] = n0;
02635         sizes[1] = n1;
02636         buildFromShapePtr(sizes, dim);
02637     }
02638 
02639     template<typename Numeric, unsigned Len, unsigned Dim>
02640     ArrayND<Numeric,Len,Dim>::ArrayND(const unsigned n0,
02641                                       const unsigned n1,
02642                                       const unsigned n2)
02643         : data_(0), strides_(0), shape_(0), len_(1UL), shapeIsKnown_(true)
02644     {
02645         const unsigned dim = 3U;
02646         unsigned sizes[dim];
02647         sizes[0] = n0;
02648         sizes[1] = n1;
02649         sizes[2] = n2;
02650         buildFromShapePtr(sizes, dim);
02651     }
02652 
02653     template<typename Numeric, unsigned Len, unsigned Dim>
02654     ArrayND<Numeric,Len,Dim>::ArrayND(const unsigned n0,
02655                                       const unsigned n1,
02656                                       const unsigned n2,
02657                                       const unsigned n3)
02658         : data_(0), strides_(0), shape_(0), len_(1UL), shapeIsKnown_(true)
02659     {
02660         const unsigned dim = 4U;
02661         unsigned sizes[dim];
02662         sizes[0] = n0;
02663         sizes[1] = n1;
02664         sizes[2] = n2;
02665         sizes[3] = n3;
02666         buildFromShapePtr(sizes, dim);
02667     }
02668 
02669     template<typename Numeric, unsigned Len, unsigned Dim>
02670     ArrayND<Numeric,Len,Dim>::ArrayND(const unsigned n0,
02671                                       const unsigned n1,
02672                                       const unsigned n2,
02673                                       const unsigned n3,
02674                                       const unsigned n4)
02675         : data_(0), strides_(0), shape_(0), len_(1UL), shapeIsKnown_(true)
02676     {
02677         const unsigned dim = 5U;
02678         unsigned sizes[dim];
02679         sizes[0] = n0;
02680         sizes[1] = n1;
02681         sizes[2] = n2;
02682         sizes[3] = n3;
02683         sizes[4] = n4;
02684         buildFromShapePtr(sizes, dim);
02685     }
02686 
02687     template<typename Numeric, unsigned Len, unsigned Dim>
02688     ArrayND<Numeric,Len,Dim>::ArrayND(const unsigned n0,
02689                                       const unsigned n1,
02690                                       const unsigned n2,
02691                                       const unsigned n3,
02692                                       const unsigned n4,
02693                                       const unsigned n5)
02694         : data_(0), strides_(0), shape_(0), len_(1UL), shapeIsKnown_(true)
02695     {
02696         const unsigned dim = 6U;
02697         unsigned sizes[dim];
02698         sizes[0] = n0;
02699         sizes[1] = n1;
02700         sizes[2] = n2;
02701         sizes[3] = n3;
02702         sizes[4] = n4;
02703         sizes[5] = n5;
02704         buildFromShapePtr(sizes, dim);
02705     }
02706 
02707     template<typename Numeric, unsigned Len, unsigned Dim>
02708     ArrayND<Numeric,Len,Dim>::ArrayND(const unsigned n0,
02709                                       const unsigned n1,
02710                                       const unsigned n2,
02711                                       const unsigned n3,
02712                                       const unsigned n4,
02713                                       const unsigned n5,
02714                                       const unsigned n6)
02715         : data_(0), strides_(0), shape_(0), len_(1UL), shapeIsKnown_(true)
02716     {
02717         const unsigned dim = 7U;
02718         unsigned sizes[dim];
02719         sizes[0] = n0;
02720         sizes[1] = n1;
02721         sizes[2] = n2;
02722         sizes[3] = n3;
02723         sizes[4] = n4;
02724         sizes[5] = n5;
02725         sizes[6] = n6;
02726         buildFromShapePtr(sizes, dim);
02727     }
02728 
02729     template<typename Numeric, unsigned Len, unsigned Dim>
02730     ArrayND<Numeric,Len,Dim>::ArrayND(const unsigned n0,
02731                                       const unsigned n1,
02732                                       const unsigned n2,
02733                                       const unsigned n3,
02734                                       const unsigned n4,
02735                                       const unsigned n5,
02736                                       const unsigned n6,
02737                                       const unsigned n7)
02738         : data_(0), strides_(0), shape_(0), len_(1UL), shapeIsKnown_(true)
02739     {
02740         const unsigned dim = 8U;
02741         unsigned sizes[dim];
02742         sizes[0] = n0;
02743         sizes[1] = n1;
02744         sizes[2] = n2;
02745         sizes[3] = n3;
02746         sizes[4] = n4;
02747         sizes[5] = n5;
02748         sizes[6] = n6;
02749         sizes[7] = n7;
02750         buildFromShapePtr(sizes, dim);
02751     }
02752 
02753     template<typename Numeric, unsigned Len, unsigned Dim>
02754     ArrayND<Numeric,Len,Dim>::ArrayND(const unsigned n0,
02755                                       const unsigned n1,
02756                                       const unsigned n2,
02757                                       const unsigned n3,
02758                                       const unsigned n4,
02759                                       const unsigned n5,
02760                                       const unsigned n6,
02761                                       const unsigned n7,
02762                                       const unsigned n8)
02763         : data_(0), strides_(0), shape_(0), len_(1UL), shapeIsKnown_(true)
02764     {
02765         const unsigned dim = 9U;
02766         unsigned sizes[dim];
02767         sizes[0] = n0;
02768         sizes[1] = n1;
02769         sizes[2] = n2;
02770         sizes[3] = n3;
02771         sizes[4] = n4;
02772         sizes[5] = n5;
02773         sizes[6] = n6;
02774         sizes[7] = n7;
02775         sizes[8] = n8;
02776         buildFromShapePtr(sizes, dim);
02777     }
02778 
02779     template<typename Numeric, unsigned Len, unsigned Dim>
02780     ArrayND<Numeric,Len,Dim>::ArrayND(const unsigned n0,
02781                                       const unsigned n1,
02782                                       const unsigned n2,
02783                                       const unsigned n3,
02784                                       const unsigned n4,
02785                                       const unsigned n5,
02786                                       const unsigned n6,
02787                                       const unsigned n7,
02788                                       const unsigned n8,
02789                                       const unsigned n9)
02790         : data_(0), strides_(0), shape_(0), len_(1UL), shapeIsKnown_(true)
02791     {
02792         const unsigned dim = 10U;
02793         unsigned sizes[dim];
02794         sizes[0] = n0;
02795         sizes[1] = n1;
02796         sizes[2] = n2;
02797         sizes[3] = n3;
02798         sizes[4] = n4;
02799         sizes[5] = n5;
02800         sizes[6] = n6;
02801         sizes[7] = n7;
02802         sizes[8] = n8;
02803         sizes[9] = n9;
02804         buildFromShapePtr(sizes, dim);
02805     }
02806 
02807     template<typename Numeric, unsigned Len, unsigned Dim>
02808     template<typename Num1, unsigned Len1, unsigned Dim1,
02809              typename Num2, unsigned Len2, unsigned Dim2>
02810     void ArrayND<Numeric,Len,Dim>::outerProductLoop(
02811         const unsigned level, unsigned long idx0,
02812         unsigned long idx1, unsigned long idx2,
02813         const ArrayND<Num1, Len1, Dim1>& a1,
02814         const ArrayND<Num2, Len2, Dim2>& a2)
02815     {
02816         const unsigned imax = shape_[level];
02817         if (level == dim_ - 1)
02818         {
02819             for (unsigned i=0; i<imax; ++i)
02820                 data_[idx0 + i] = a1.data_[idx1]*a2.data_[idx2 + i];
02821         }
02822         else
02823         {
02824             for (unsigned i=0; i<imax; ++i)
02825             {
02826                 outerProductLoop(level+1, idx0, idx1, idx2, a1, a2);
02827                 idx0 += strides_[level];
02828                 if (level < a1.dim_)
02829                     idx1 += a1.strides_[level];
02830                 else
02831                     idx2 += a2.strides_[level - a1.dim_];
02832             }                                 
02833         }
02834     }
02835 
02836     template<typename Numeric, unsigned Len, unsigned Dim>
02837     template<typename Num1, unsigned Len1, unsigned Dim1,
02838              typename Num2, unsigned Len2, unsigned Dim2>
02839     ArrayND<Numeric,Len,Dim>::ArrayND(const ArrayND<Num1, Len1, Dim1>& a1,
02840                                       const ArrayND<Num2, Len2, Dim2>& a2)
02841         : data_(0), strides_(0), shape_(0),
02842           len_(1UL), dim_(a1.dim_ + a2.dim_), shapeIsKnown_(true)
02843     {
02844         if (!(a1.shapeIsKnown_ && a2.shapeIsKnown_))
02845             throw npstat::NpstatInvalidArgument(
02846                 "In npstat::ArrayND outer product constructor: "
02847                 "uninitialized argument array");
02848         if (dim_)
02849         {
02850             shape_ = makeBuffer(dim_, localShape_, Dim);
02851             copyBuffer(shape_, a1.shape_, a1.dim_);
02852             copyBuffer(shape_+a1.dim_, a2.shape_, a2.dim_);
02853 
02854             for (unsigned i=0; i<dim_; ++i)
02855             {
02856                 assert(shape_[i]);
02857                 len_ *= shape_[i];
02858             }
02859 
02860             // Figure out the array strides
02861             buildStrides();
02862 
02863             // Allocate the data array
02864             data_ = makeBuffer(len_, localData_, Len);
02865 
02866             // Fill the data array
02867             if (a1.dim_ == 0)
02868             {
02869                 for (unsigned long i=0; i<len_; ++i)
02870                     data_[i] = a1.localData_[0] * a2.data_[i];
02871             }
02872             else if (a2.dim_ == 0)
02873             {
02874                 for (unsigned long i=0; i<len_; ++i)
02875                     data_[i] = a1.data_[i] * a2.localData_[0];
02876             }
02877             else
02878                 outerProductLoop(0U, 0UL, 0UL, 0UL, a1, a2);
02879         }
02880         else
02881         {
02882             localData_[0] = a1.localData_[0] * a2.localData_[0];
02883             data_ = localData_;
02884         }
02885     }
02886 
02887     template<typename Numeric, unsigned Len, unsigned Dim>
02888     inline ArrayND<Numeric,Len,Dim>::~ArrayND()
02889     {
02890         destroyBuffer(data_, localData_);
02891         destroyBuffer(strides_, localStrides_);
02892         destroyBuffer(shape_, localShape_);
02893     }
02894 
02895     template<typename Numeric, unsigned Len, unsigned Dim>
02896     ArrayND<Numeric,Len,Dim>&
02897     ArrayND<Numeric,Len,Dim>::operator=(const ArrayND& r)
02898     {
02899         if (this == &r)
02900             return *this;
02901         if (shapeIsKnown_)
02902         {
02903             if (!r.shapeIsKnown_) throw npstat::NpstatInvalidArgument(
02904                 "In npstat::ArrayND assignment operator: "
02905                 "uninitialized argument array");
02906             if (!isShapeCompatible(r)) throw npstat::NpstatInvalidArgument(
02907                 "In npstat::ArrayND assignment operator: "
02908                 "incompatible argument array shape");
02909             if (dim_)
02910                 copyBuffer(data_, r.data_, len_);
02911             else
02912                 localData_[0] = r.localData_[0];
02913         }
02914         else
02915         {
02916             // This object is uninitialized. If the object on the
02917             // right is itself initialized, make an in-place copy.
02918             if (r.shapeIsKnown_)
02919                 new (this) ArrayND(r);
02920         }
02921         return *this;
02922     }
02923 
02924     template<typename Numeric, unsigned Len, unsigned Dim>
02925     template <typename Num2, unsigned Len2, unsigned Dim2>
02926     ArrayND<Numeric,Len,Dim>&
02927     ArrayND<Numeric,Len,Dim>::operator=(const ArrayND<Num2,Len2,Dim2>& r)
02928     {
02929         if ((void*)this == (void*)(&r))
02930             return *this;
02931         if (shapeIsKnown_)
02932         {
02933             if (!r.shapeIsKnown_) throw npstat::NpstatInvalidArgument(
02934                 "In npstat::ArrayND assignment operator: "
02935                 "uninitialized argument array");
02936             if (!isShapeCompatible(r)) throw npstat::NpstatInvalidArgument(
02937                 "In npstat::ArrayND assignment operator: "
02938                 "incompatible argument array shape");
02939             if (dim_)
02940                 copyBuffer(data_, r.data_, len_);
02941             else
02942                 localData_[0] = static_cast<Numeric>(r.localData_[0]);
02943         }
02944         else
02945         {
02946             // This object is uninitialized. If the object on the
02947             // right is itself initialized, make an in-place copy.
02948             if (r.shapeIsKnown_)
02949                 new (this) ArrayND(r);
02950         }
02951         return *this;
02952     }
02953 
02954     template<typename Numeric, unsigned Len, unsigned Dim>
02955     template <typename Num2, unsigned Len2, unsigned Dim2, class Functor>
02956     ArrayND<Numeric,Len,Dim>&
02957     ArrayND<Numeric,Len,Dim>::assign(const ArrayND<Num2,Len2,Dim2>& r,
02958                                      Functor f)
02959     {
02960         if (shapeIsKnown_)
02961         {
02962             if (!r.shapeIsKnown_) throw npstat::NpstatInvalidArgument(
02963                 "In npstat::ArrayND::assign: uninitialized argument array");
02964             if (!isShapeCompatible(r)) throw npstat::NpstatInvalidArgument(
02965                 "In npstat::ArrayND::assign: incompatible argument array shape");
02966             if (dim_)
02967                 for (unsigned long i=0; i<len_; ++i)
02968                     data_[i] = static_cast<Numeric>(f(r.data_[i]));
02969             else
02970                 localData_[0] = static_cast<Numeric>(f(r.localData_[0]));
02971         }
02972         else
02973         {
02974             // This object is uninitialized. If the object on the
02975             // right is itself initialized, build new array in place.
02976             if (r.shapeIsKnown_)
02977                 new (this) ArrayND(r, f);
02978         }
02979         return *this;
02980     }
02981 
02982     template<typename Numeric, unsigned Len, unsigned Dim>
02983     inline ArrayShape ArrayND<Numeric,Len,Dim>::shape() const
02984     {
02985         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
02986             "Initialize npstat::ArrayND before calling method \"shape\"");
02987         return ArrayShape(shape_, shape_+dim_);
02988     }
02989 
02990     template<typename Numeric, unsigned Len, unsigned Dim>
02991     inline ArrayRange ArrayND<Numeric,Len,Dim>::fullRange() const
02992     {
02993         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
02994             "Initialize npstat::ArrayND before calling method \"fullRange\"");
02995         ArrayRange range;
02996         if (dim_)
02997         {
02998             range.reserve(dim_);
02999             for (unsigned i=0; i<dim_; ++i)
03000                 range.push_back(Interval<unsigned>(0U, shape_[i]));
03001         }
03002         return range;
03003     }
03004 
03005     template<typename Numeric, unsigned Len, unsigned Dim>
03006     bool ArrayND<Numeric,Len,Dim>::isDensity() const
03007     {
03008         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03009             "Initialize npstat::ArrayND before calling method \"isDensity\"");
03010         const Numeric zero = Numeric();
03011         bool hasPositive = false;
03012         if (dim_)
03013             for (unsigned long i=0; i<len_; ++i)
03014             {
03015                 // Don't make comparisons whose result can be
03016                 // determined in advance by assuming that Numeric
03017                 // is an unsigned type. Some compilers will
03018                 // complain about it when this template is
03019                 // instantiated with such a type.
03020                 if (data_[i] == zero)
03021                     continue;
03022                 if (ComplexComparesFalse<Numeric>::less(zero, data_[i]))
03023                     hasPositive = true;
03024                 else
03025                     return false;
03026             }
03027         else
03028             hasPositive = ComplexComparesFalse<Numeric>::less(
03029                 zero, localData_[0]);
03030         return hasPositive;
03031     }
03032 
03033     template<typename Numeric, unsigned Len, unsigned Dim>
03034     bool ArrayND<Numeric,Len,Dim>::isZero() const
03035     {
03036         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03037             "Initialize npstat::ArrayND before calling method \"isZero\"");
03038         const Numeric zero = Numeric();
03039         if (dim_)
03040         {
03041             for (unsigned long i=0; i<len_; ++i)
03042                 if (data_[i] != zero)
03043                     return false;
03044         }
03045         else
03046             if (localData_[0] != zero)
03047                 return false;
03048         return true;
03049     }
03050 
03051     template<typename Numeric, unsigned Len, unsigned Dim>
03052     void ArrayND<Numeric,Len,Dim>::convertLinearIndex(
03053         unsigned long l, unsigned* idx, const unsigned idxLen) const
03054     {
03055         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03056             "Initialize npstat::ArrayND before calling "
03057             "method \"convertLinearIndex\"");
03058         if (!dim_) throw npstat::NpstatInvalidArgument(
03059             "npstat::ArrayND::convertLinearIndex method "
03060             "can not be used with array of 0 rank");
03061         if (idxLen != dim_) throw npstat::NpstatInvalidArgument(
03062             "In npstat::ArrayND::convertLinearIndex: incompatible index length");
03063         if (l >= len_) throw npstat::NpstatOutOfRange(
03064             "In npstat::ArrayND::convertLinearIndex: linear index out of range");
03065         assert(idx);
03066 
03067         for (unsigned i=0; i<dim_; ++i)
03068         {
03069             idx[i] = l / strides_[i];
03070             l -= (idx[i] * strides_[i]);
03071         }
03072     }
03073 
03074     template<typename Numeric, unsigned Len, unsigned Dim>
03075     unsigned long ArrayND<Numeric,Len,Dim>::linearIndex(
03076         const unsigned* index, unsigned idxLen) const
03077     {
03078         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03079             "Initialize npstat::ArrayND before calling method \"linearIndex\"");
03080         if (!dim_) throw npstat::NpstatInvalidArgument(
03081             "npstat::ArrayND::linearIndex method "
03082             "can not be used with array of 0 rank");
03083         if (idxLen != dim_) throw npstat::NpstatInvalidArgument(
03084             "In npstat::ArrayND::linearIndex: incompatible index length");
03085         assert(index);
03086 
03087         unsigned long idx = 0UL;
03088         for (unsigned i=0; i<dim_; ++i)
03089         {
03090             if (index[i] >= shape_[i])
03091                 throw npstat::NpstatOutOfRange(
03092                     "In npstat::ArrayND::linearIndex: index out of range");
03093             idx += index[i]*strides_[i];
03094         }
03095         return idx;
03096     }
03097 
03098     template<typename Numeric, unsigned Len, unsigned Dim>
03099     inline Numeric& ArrayND<Numeric,Len,Dim>::value(
03100         const unsigned *index, const unsigned dim)
03101     {
03102         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03103             "Initialize npstat::ArrayND before calling method \"value\"");
03104         if (dim != dim_) throw npstat::NpstatInvalidArgument(
03105             "In npstat::ArrayND::value: incompatible index length");
03106         if (dim)
03107         {
03108             assert(index);
03109             unsigned long idx = 0UL;
03110             for (unsigned i=0; i<dim_; ++i)
03111                 idx += index[i]*strides_[i];
03112             return data_[idx];
03113         }
03114         else
03115             return localData_[0];
03116     }
03117 
03118     template<typename Numeric, unsigned Len, unsigned Dim>
03119     inline const Numeric& ArrayND<Numeric,Len,Dim>::value(
03120         const unsigned *index, const unsigned dim) const
03121     {
03122         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03123             "Initialize npstat::ArrayND before calling method \"value\"");
03124         if (dim != dim_) throw npstat::NpstatInvalidArgument(
03125             "In npstat::ArrayND::value: incompatible index length");
03126         if (dim)
03127         {
03128             assert(index);
03129             unsigned long idx = 0UL;
03130             for (unsigned i=0; i<dim_; ++i)
03131                 idx += index[i]*strides_[i];
03132             return data_[idx];
03133         }
03134         else
03135             return localData_[0];
03136     }
03137 
03138     template<typename Numeric, unsigned Len, unsigned Dim>
03139     inline Numeric& ArrayND<Numeric,Len,Dim>::linearValue(
03140         const unsigned long index)
03141     {
03142         return data_[index];
03143     }
03144 
03145     template<typename Numeric, unsigned Len, unsigned Dim>
03146     inline const Numeric& ArrayND<Numeric,Len,Dim>::linearValue(
03147         const unsigned long index) const
03148     {
03149         return data_[index];
03150     }
03151 
03152     template<typename Numeric, unsigned Len, unsigned Dim>
03153     inline Numeric& ArrayND<Numeric,Len,Dim>::linearValueAt(
03154         const unsigned long index)
03155     {
03156         if (index >= len_)
03157             throw npstat::NpstatOutOfRange(
03158                 "In npstat::ArrayND::linearValueAt: linear index out of range");
03159         return data_[index];
03160     }
03161 
03162     template<typename Numeric, unsigned Len, unsigned Dim>
03163     inline const Numeric& ArrayND<Numeric,Len,Dim>::linearValueAt(
03164         const unsigned long index) const
03165     {
03166         if (index >= len_)
03167             throw npstat::NpstatOutOfRange(
03168                 "In npstat::ArrayND::linearValueAt: linear index out of range");
03169         return data_[index];
03170     }
03171 
03172     template<typename Numeric, unsigned Len, unsigned Dim>
03173     inline unsigned ArrayND<Numeric,Len,Dim>::coordToIndex(
03174         const double x, const unsigned idim) const
03175     {
03176         if (x <= 0.0)
03177             return 0;
03178         else if (x >= static_cast<double>(shape_[idim] - 1))
03179             return shape_[idim] - 1;
03180         else
03181             return static_cast<unsigned>(std::floor(x + 0.5));
03182     }
03183 
03184     template<typename Numeric, unsigned Len, unsigned Dim>
03185     inline const Numeric& ArrayND<Numeric,Len,Dim>::closest(
03186         const double *x, const unsigned dim) const
03187     {
03188         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03189             "Initialize npstat::ArrayND before calling method \"closest\"");
03190         if (dim != dim_) throw npstat::NpstatInvalidArgument(
03191             "In npstat::ArrayND::closest: incompatible data length");
03192         if (dim)
03193         {
03194             assert(x);
03195             unsigned long idx = 0UL;
03196             for (unsigned i=0; i<dim_; ++i)
03197                 idx += coordToIndex(x[i], i)*strides_[i];
03198             return data_[idx];
03199         }
03200         else
03201             return localData_[0];
03202     }
03203 
03204     template<typename Numeric, unsigned Len, unsigned Dim>
03205     inline Numeric& ArrayND<Numeric,Len,Dim>::closest(
03206         const double *x, const unsigned dim)
03207     {
03208         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03209             "Initialize npstat::ArrayND before calling method \"closest\"");
03210         if (dim != dim_) throw npstat::NpstatInvalidArgument(
03211             "In npstat::ArrayND::closest: incompatible data length");
03212         if (dim)
03213         {
03214             assert(x);
03215             unsigned long idx = 0UL;
03216             for (unsigned i=0; i<dim_; ++i)
03217                 idx += coordToIndex(x[i], i)*strides_[i];
03218             return data_[idx];
03219         }
03220         else
03221             return localData_[0];
03222     }
03223 
03224     template<typename Numeric, unsigned Len, unsigned Dim>
03225     inline const Numeric& ArrayND<Numeric,Len,Dim>::valueAt(
03226         const unsigned *index, const unsigned dim) const
03227     {
03228         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03229             "Initialize npstat::ArrayND before calling method \"valueAt\"");
03230         if (dim != dim_) throw npstat::NpstatInvalidArgument(
03231             "In npstat::ArrayND::valueAt: incompatible index length");
03232         if (dim)
03233         {
03234             assert(index);
03235             unsigned long idx = 0UL;
03236             for (unsigned i=0; i<dim_; ++i)
03237             {
03238                 if (index[i] >= shape_[i]) throw npstat::NpstatOutOfRange(
03239                     "In npstat::ArrayND::valueAt: index out of range");
03240                 idx += index[i]*strides_[i];
03241             }
03242             return data_[idx];
03243         }
03244         else
03245             return localData_[0];
03246     }
03247 
03248     template<typename Numeric, unsigned Len, unsigned Dim>
03249     inline Numeric& ArrayND<Numeric,Len,Dim>::valueAt(
03250         const unsigned *index, const unsigned dim)
03251     {
03252         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03253             "Initialize npstat::ArrayND before calling method \"valueAt\"");
03254         if (dim != dim_) throw npstat::NpstatInvalidArgument(
03255             "In npstat::ArrayND::valueAt: incompatible index length");
03256         if (dim)
03257         {
03258             assert(index);
03259             unsigned long idx = 0UL;
03260             for (unsigned i=0; i<dim_; ++i)
03261             {
03262                 if (index[i] >= shape_[i]) throw npstat::NpstatOutOfRange(
03263                     "In npstat::ArrayND::valueAt: index out of range");
03264                 idx += index[i]*strides_[i];
03265             }
03266             return data_[idx];
03267         }
03268         else
03269             return localData_[0];
03270     }
03271 
03272     template<typename Numeric, unsigned Len, unsigned Dim>
03273     inline Numeric& ArrayND<Numeric,Len,Dim>::operator()()
03274     {
03275         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03276             "Initialize npstat::ArrayND before calling method \"operator()\"");
03277         if (dim_) throw npstat::NpstatInvalidArgument(
03278             "In npstat::ArrayND::operator(): wrong # of args (not rank 0 array)");
03279         return localData_[0];
03280     }
03281 
03282     template<typename Numeric, unsigned Len, unsigned Dim>
03283     inline const Numeric& ArrayND<Numeric,Len,Dim>::operator()() const
03284     {
03285         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03286             "Initialize npstat::ArrayND before calling method \"operator()\"");
03287         if (dim_) throw npstat::NpstatInvalidArgument(
03288             "In npstat::ArrayND::operator(): wrong # of args (not rank 0 array)");
03289         return localData_[0];
03290     }
03291 
03292     template<typename Numeric, unsigned Len, unsigned Dim>
03293     inline Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03294         const unsigned i)
03295     {
03296         if (1U != dim_) throw npstat::NpstatInvalidArgument(
03297             "In npstat::ArrayND::operator(): wrong # of args (not rank 1 array)");
03298         return data_[i];
03299     }
03300 
03301     template<typename Numeric, unsigned Len, unsigned Dim>
03302     inline const Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03303         const unsigned i) const
03304     {
03305         if (1U != dim_) throw npstat::NpstatInvalidArgument(
03306             "In npstat::ArrayND::operator(): wrong # of args (not rank 1 array)");
03307         return data_[i];
03308     }
03309 
03310     template<typename Numeric, unsigned Len, unsigned Dim>
03311     const Numeric& ArrayND<Numeric,Len,Dim>::at() const
03312     {
03313         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03314             "Initialize npstat::ArrayND before calling method \"at\"");
03315         if (dim_) throw npstat::NpstatInvalidArgument(
03316             "In npstat::ArrayND::at: wrong # of args (not rank 0 array)");
03317         return localData_[0];
03318     }
03319 
03320     template<typename Numeric, unsigned Len, unsigned Dim>
03321     Numeric& ArrayND<Numeric,Len,Dim>::at()
03322     {
03323         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
03324             "Initialize npstat::ArrayND before calling method \"at\"");
03325         if (dim_) throw npstat::NpstatInvalidArgument(
03326             "In npstat::ArrayND::at: wrong # of args (not rank 0 array)");
03327         return localData_[0];
03328     }
03329 
03330     template<typename Numeric, unsigned Len, unsigned Dim>
03331     const Numeric& ArrayND<Numeric,Len,Dim>::at(
03332         const unsigned i0) const
03333     {
03334         if (1U != dim_) throw npstat::NpstatInvalidArgument(
03335             "In npstat::ArrayND::at: wrong # of args (not rank 1 array)");
03336         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03337             "In npstat::ArrayND::at: index 0 out of range (rank 1)");
03338         return data_[i0];
03339     }
03340 
03341     template<typename Numeric, unsigned Len, unsigned Dim>
03342     Numeric& ArrayND<Numeric,Len,Dim>::at(
03343         const unsigned i0)
03344     {
03345         if (1U != dim_) throw npstat::NpstatInvalidArgument(
03346             "In npstat::ArrayND::at: wrong # of args (not rank 1 array)");
03347         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03348             "In npstat::ArrayND::at: index 0 out of range (rank 1)");
03349         return data_[i0];
03350     }
03351 
03352     template<typename Numeric, unsigned Len, unsigned Dim>
03353     inline Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03354         const unsigned i0,
03355         const unsigned i1)
03356     {
03357         if (2U != dim_) throw npstat::NpstatInvalidArgument(
03358             "In npstat::ArrayND::operator(): wrong # of args (not rank 2 array)");
03359         return data_[i0*strides_[0] + i1];
03360     }
03361 
03362     template<typename Numeric, unsigned Len, unsigned Dim>
03363     inline const Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03364         const unsigned i0,
03365         const unsigned i1) const
03366     {
03367         if (2U != dim_) throw npstat::NpstatInvalidArgument(
03368             "In npstat::ArrayND::operator(): wrong # of args (not rank 2 array)");
03369         return data_[i0*strides_[0] + i1];
03370     }
03371 
03372     template<typename Numeric, unsigned Len, unsigned Dim>
03373     const Numeric& ArrayND<Numeric,Len,Dim>::at(
03374         const unsigned i0,
03375         const unsigned i1) const
03376     {
03377         if (2U != dim_) throw npstat::NpstatInvalidArgument(
03378             "In npstat::ArrayND::at: wrong # of args (not rank 2 array)");
03379         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03380             "In npstat::ArrayND::at: index 0 out of range (rank 2)");
03381         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03382             "In npstat::ArrayND::at: index 1 out of range (rank 2)");
03383         return data_[i0*strides_[0] + i1];
03384     }
03385 
03386     template<typename Numeric, unsigned Len, unsigned Dim>
03387     Numeric& ArrayND<Numeric,Len,Dim>::at(
03388         const unsigned i0,
03389         const unsigned i1)
03390     {
03391         if (2U != dim_) throw npstat::NpstatInvalidArgument(
03392             "In npstat::ArrayND::at: wrong # of args (not rank 2 array)");
03393         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03394             "In npstat::ArrayND::at: index 0 out of range (rank 2)");
03395         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03396             "In npstat::ArrayND::at: index 1 out of range (rank 2)");
03397         return data_[i0*strides_[0] + i1];
03398     }
03399 
03400     template<typename Numeric, unsigned Len, unsigned Dim>
03401     inline const Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03402         const unsigned i0,
03403         const unsigned i1,
03404         const unsigned i2) const 
03405     {
03406         if (3U != dim_) throw npstat::NpstatInvalidArgument(
03407             "In npstat::ArrayND::operator(): wrong # of args (not rank 3 array)");
03408         return data_[i0*strides_[0] + i1*strides_[1] + i2];
03409     }
03410 
03411     template<typename Numeric, unsigned Len, unsigned Dim>
03412     inline const Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03413         const unsigned i0,
03414         const unsigned i1,
03415         const unsigned i2,
03416         const unsigned i3) const 
03417     {
03418         if (4U != dim_) throw npstat::NpstatInvalidArgument(
03419             "In npstat::ArrayND::operator(): wrong # of args (not rank 4 array)");
03420         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + i3];
03421     }
03422 
03423     template<typename Numeric, unsigned Len, unsigned Dim>
03424     inline const Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03425         const unsigned i0,
03426         const unsigned i1,
03427         const unsigned i2,
03428         const unsigned i3,
03429         const unsigned i4) const 
03430     {
03431         if (5U != dim_) throw npstat::NpstatInvalidArgument(
03432             "In npstat::ArrayND::operator(): wrong # of args (not rank 5 array)");
03433         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03434                      i3*strides_[3] + i4];
03435     }
03436 
03437     template<typename Numeric, unsigned Len, unsigned Dim>
03438     inline const Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03439         const unsigned i0,
03440         const unsigned i1,
03441         const unsigned i2,
03442         const unsigned i3,
03443         const unsigned i4,
03444         const unsigned i5) const 
03445     {
03446         if (6U != dim_) throw npstat::NpstatInvalidArgument(
03447             "In npstat::ArrayND::operator(): wrong # of args (not rank 6 array)");
03448         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03449                      i3*strides_[3] + i4*strides_[4] + i5];
03450     }
03451 
03452     template<typename Numeric, unsigned Len, unsigned Dim>
03453     inline const Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03454         const unsigned i0,
03455         const unsigned i1,
03456         const unsigned i2,
03457         const unsigned i3,
03458         const unsigned i4,
03459         const unsigned i5,
03460         const unsigned i6) const 
03461     {
03462         if (7U != dim_) throw npstat::NpstatInvalidArgument(
03463             "In npstat::ArrayND::operator(): wrong # of args (not rank 7 array)");
03464         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03465                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] + i6];
03466     }
03467 
03468     template<typename Numeric, unsigned Len, unsigned Dim>
03469     inline const Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03470         const unsigned i0,
03471         const unsigned i1,
03472         const unsigned i2,
03473         const unsigned i3,
03474         const unsigned i4,
03475         const unsigned i5,
03476         const unsigned i6,
03477         const unsigned i7) const 
03478     {
03479         if (8U != dim_) throw npstat::NpstatInvalidArgument(
03480             "In npstat::ArrayND::operator(): wrong # of args (not rank 8 array)");
03481         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03482                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] +
03483                      i6*strides_[6] + i7];
03484     }
03485 
03486     template<typename Numeric, unsigned Len, unsigned Dim>
03487     inline const Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03488         const unsigned i0,
03489         const unsigned i1,
03490         const unsigned i2,
03491         const unsigned i3,
03492         const unsigned i4,
03493         const unsigned i5,
03494         const unsigned i6,
03495         const unsigned i7,
03496         const unsigned i8) const 
03497     {
03498         if (9U != dim_) throw npstat::NpstatInvalidArgument(
03499             "In npstat::ArrayND::operator(): wrong # of args (not rank 9 array)");
03500         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03501                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] +
03502                      i6*strides_[6] + i7*strides_[7] + i8];
03503     }
03504 
03505     template<typename Numeric, unsigned Len, unsigned Dim>
03506     inline const Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03507         const unsigned i0,
03508         const unsigned i1,
03509         const unsigned i2,
03510         const unsigned i3,
03511         const unsigned i4,
03512         const unsigned i5,
03513         const unsigned i6,
03514         const unsigned i7,
03515         const unsigned i8,
03516         const unsigned i9) const 
03517     {
03518         if (10U != dim_) throw npstat::NpstatInvalidArgument(
03519             "In npstat::ArrayND::operator(): wrong # of args (not rank 10 array)");
03520         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03521                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] +
03522                      i6*strides_[6] + i7*strides_[7] + i8*strides_[8] + i9];
03523     }
03524 
03525     template<typename Numeric, unsigned Len, unsigned Dim>
03526     inline Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03527         const unsigned i0,
03528         const unsigned i1,
03529         const unsigned i2)
03530     {
03531         if (3U != dim_) throw npstat::NpstatInvalidArgument(
03532             "In npstat::ArrayND::operator(): wrong # of args (not rank 3 array)");
03533         return data_[i0*strides_[0] + i1*strides_[1] + i2];
03534     }
03535 
03536     template<typename Numeric, unsigned Len, unsigned Dim>
03537     inline Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03538         const unsigned i0,
03539         const unsigned i1,
03540         const unsigned i2,
03541         const unsigned i3)
03542     {
03543         if (4U != dim_) throw npstat::NpstatInvalidArgument(
03544             "In npstat::ArrayND::operator(): wrong # of args (not rank 4 array)");
03545         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + i3];
03546     }
03547 
03548     template<typename Numeric, unsigned Len, unsigned Dim>
03549     inline Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03550         const unsigned i0,
03551         const unsigned i1,
03552         const unsigned i2,
03553         const unsigned i3,
03554         const unsigned i4)
03555     {
03556         if (5U != dim_) throw npstat::NpstatInvalidArgument(
03557             "In npstat::ArrayND::operator(): wrong # of args (not rank 5 array)");
03558         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03559                      i3*strides_[3] + i4];
03560     }
03561 
03562     template<typename Numeric, unsigned Len, unsigned Dim>
03563     inline Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03564         const unsigned i0,
03565         const unsigned i1,
03566         const unsigned i2,
03567         const unsigned i3,
03568         const unsigned i4,
03569         const unsigned i5)
03570     {
03571         if (6U != dim_) throw npstat::NpstatInvalidArgument(
03572             "In npstat::ArrayND::operator(): wrong # of args (not rank 6 array)");
03573         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03574                      i3*strides_[3] + i4*strides_[4] + i5];
03575     }
03576 
03577     template<typename Numeric, unsigned Len, unsigned Dim>
03578     inline Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03579         const unsigned i0,
03580         const unsigned i1,
03581         const unsigned i2,
03582         const unsigned i3,
03583         const unsigned i4,
03584         const unsigned i5,
03585         const unsigned i6)
03586     {
03587         if (7U != dim_) throw npstat::NpstatInvalidArgument(
03588             "In npstat::ArrayND::operator(): wrong # of args (not rank 7 array)");
03589         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03590                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] + i6];
03591     }
03592 
03593     template<typename Numeric, unsigned Len, unsigned Dim>
03594     inline Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03595         const unsigned i0,
03596         const unsigned i1,
03597         const unsigned i2,
03598         const unsigned i3,
03599         const unsigned i4,
03600         const unsigned i5,
03601         const unsigned i6,
03602         const unsigned i7)
03603     {
03604         if (8U != dim_) throw npstat::NpstatInvalidArgument(
03605             "In npstat::ArrayND::operator(): wrong # of args (not rank 8 array)");
03606         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03607                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] +
03608                      i6*strides_[6] + i7];
03609     }
03610 
03611     template<typename Numeric, unsigned Len, unsigned Dim>
03612     inline Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03613         const unsigned i0,
03614         const unsigned i1,
03615         const unsigned i2,
03616         const unsigned i3,
03617         const unsigned i4,
03618         const unsigned i5,
03619         const unsigned i6,
03620         const unsigned i7,
03621         const unsigned i8)
03622     {
03623         if (9U != dim_) throw npstat::NpstatInvalidArgument(
03624             "In npstat::ArrayND::operator(): wrong # of args (not rank 9 array)");
03625         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03626                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] +
03627                      i6*strides_[6] + i7*strides_[7] + i8];
03628     }
03629 
03630     template<typename Numeric, unsigned Len, unsigned Dim>
03631     inline Numeric& ArrayND<Numeric,Len,Dim>::operator()(
03632         const unsigned i0,
03633         const unsigned i1,
03634         const unsigned i2,
03635         const unsigned i3,
03636         const unsigned i4,
03637         const unsigned i5,
03638         const unsigned i6,
03639         const unsigned i7,
03640         const unsigned i8,
03641         const unsigned i9)
03642     {
03643         if (10U != dim_) throw npstat::NpstatInvalidArgument(
03644             "In npstat::ArrayND::operator(): wrong # of args (not rank 10 array)");
03645         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03646                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] +
03647                      i6*strides_[6] + i7*strides_[7] + i8*strides_[8] + i9];
03648     }
03649 
03650     template<typename Numeric, unsigned Len, unsigned Dim>
03651     const Numeric& ArrayND<Numeric,Len,Dim>::at(
03652         const unsigned i0,
03653         const unsigned i1,
03654         const unsigned i2) const 
03655     {
03656         if (3U != dim_) throw npstat::NpstatInvalidArgument(
03657             "In npstat::ArrayND::at: wrong # of args (not rank 3 array)");
03658         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03659             "In npstat::ArrayND::at: index 0 out of range (rank 3)");
03660         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03661             "In npstat::ArrayND::at: index 1 out of range (rank 3)");
03662         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
03663             "In npstat::ArrayND::at: index 2 out of range (rank 3)");
03664         return data_[i0*strides_[0] + i1*strides_[1] + i2];
03665     }
03666 
03667     template<typename Numeric, unsigned Len, unsigned Dim>
03668     const Numeric& ArrayND<Numeric,Len,Dim>::at(
03669         const unsigned i0,
03670         const unsigned i1,
03671         const unsigned i2,
03672         const unsigned i3) const 
03673     {
03674         if (4U != dim_) throw npstat::NpstatInvalidArgument(
03675             "In npstat::ArrayND::at: wrong # of args (not rank 4 array)");
03676         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03677             "In npstat::ArrayND::at: index 0 out of range (rank 4)");
03678         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03679             "In npstat::ArrayND::at: index 1 out of range (rank 4)");
03680         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
03681             "In npstat::ArrayND::at: index 2 out of range (rank 4)");
03682         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
03683             "In npstat::ArrayND::at: index 3 out of range (rank 4)");
03684         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + i3];
03685     }
03686 
03687     template<typename Numeric, unsigned Len, unsigned Dim>
03688     const Numeric& ArrayND<Numeric,Len,Dim>::at(
03689         const unsigned i0,
03690         const unsigned i1,
03691         const unsigned i2,
03692         const unsigned i3,
03693         const unsigned i4) const 
03694     {
03695         if (5U != dim_) throw npstat::NpstatInvalidArgument(
03696             "In npstat::ArrayND::at: wrong # of args (not rank 5 array)");
03697         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03698             "In npstat::ArrayND::at: index 0 out of range (rank 5)");
03699         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03700             "In npstat::ArrayND::at: index 1 out of range (rank 5)");
03701         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
03702             "In npstat::ArrayND::at: index 2 out of range (rank 5)");
03703         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
03704             "In npstat::ArrayND::at: index 3 out of range (rank 5)");
03705         if (i4 >= shape_[4]) throw npstat::NpstatOutOfRange(
03706             "In npstat::ArrayND::at: index 4 out of range (rank 5)");
03707         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03708                      i3*strides_[3] + i4];
03709     }
03710 
03711     template<typename Numeric, unsigned Len, unsigned Dim>
03712     const Numeric& ArrayND<Numeric,Len,Dim>::at(
03713         const unsigned i0,
03714         const unsigned i1,
03715         const unsigned i2,
03716         const unsigned i3,
03717         const unsigned i4,
03718         const unsigned i5) const 
03719     {
03720         if (6U != dim_) throw npstat::NpstatInvalidArgument(
03721             "In npstat::ArrayND::at: wrong # of args (not rank 6 array)");
03722         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03723             "In npstat::ArrayND::at: index 0 out of range (rank 6)");
03724         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03725             "In npstat::ArrayND::at: index 1 out of range (rank 6)");
03726         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
03727             "In npstat::ArrayND::at: index 2 out of range (rank 6)");
03728         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
03729             "In npstat::ArrayND::at: index 3 out of range (rank 6)");
03730         if (i4 >= shape_[4]) throw npstat::NpstatOutOfRange(
03731             "In npstat::ArrayND::at: index 4 out of range (rank 6)");
03732         if (i5 >= shape_[5]) throw npstat::NpstatOutOfRange(
03733             "In npstat::ArrayND::at: index 5 out of range (rank 6)");
03734         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03735                      i3*strides_[3] + i4*strides_[4] + i5];
03736     }
03737 
03738     template<typename Numeric, unsigned Len, unsigned Dim>
03739     const Numeric& ArrayND<Numeric,Len,Dim>::at(
03740         const unsigned i0,
03741         const unsigned i1,
03742         const unsigned i2,
03743         const unsigned i3,
03744         const unsigned i4,
03745         const unsigned i5,
03746         const unsigned i6) const 
03747     {
03748         if (7U != dim_) throw npstat::NpstatInvalidArgument(
03749             "In npstat::ArrayND::at: wrong # of args (not rank 7 array)");
03750         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03751             "In npstat::ArrayND::at: index 0 out of range (rank 7)");
03752         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03753             "In npstat::ArrayND::at: index 1 out of range (rank 7)");
03754         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
03755             "In npstat::ArrayND::at: index 2 out of range (rank 7)");
03756         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
03757             "In npstat::ArrayND::at: index 3 out of range (rank 7)");
03758         if (i4 >= shape_[4]) throw npstat::NpstatOutOfRange(
03759             "In npstat::ArrayND::at: index 4 out of range (rank 7)");
03760         if (i5 >= shape_[5]) throw npstat::NpstatOutOfRange(
03761             "In npstat::ArrayND::at: index 5 out of range (rank 7)");
03762         if (i6 >= shape_[6]) throw npstat::NpstatOutOfRange(
03763             "In npstat::ArrayND::at: index 6 out of range (rank 7)");
03764         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03765                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] + i6];
03766     }
03767 
03768     template<typename Numeric, unsigned Len, unsigned Dim>
03769     const Numeric& ArrayND<Numeric,Len,Dim>::at(
03770         const unsigned i0,
03771         const unsigned i1,
03772         const unsigned i2,
03773         const unsigned i3,
03774         const unsigned i4,
03775         const unsigned i5,
03776         const unsigned i6,
03777         const unsigned i7) const 
03778     {
03779         if (8U != dim_) throw npstat::NpstatInvalidArgument(
03780             "In npstat::ArrayND::at: wrong # of args (not rank 8 array)");
03781         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03782             "In npstat::ArrayND::at: index 0 out of range (rank 8)");
03783         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03784             "In npstat::ArrayND::at: index 1 out of range (rank 8)");
03785         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
03786             "In npstat::ArrayND::at: index 2 out of range (rank 8)");
03787         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
03788             "In npstat::ArrayND::at: index 3 out of range (rank 8)");
03789         if (i4 >= shape_[4]) throw npstat::NpstatOutOfRange(
03790             "In npstat::ArrayND::at: index 4 out of range (rank 8)");
03791         if (i5 >= shape_[5]) throw npstat::NpstatOutOfRange(
03792             "In npstat::ArrayND::at: index 5 out of range (rank 8)");
03793         if (i6 >= shape_[6]) throw npstat::NpstatOutOfRange(
03794             "In npstat::ArrayND::at: index 6 out of range (rank 8)");
03795         if (i7 >= shape_[7]) throw npstat::NpstatOutOfRange(
03796             "In npstat::ArrayND::at: index 7 out of range (rank 8)");
03797         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03798                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] +
03799                      i6*strides_[6] + i7];
03800     }
03801 
03802     template<typename Numeric, unsigned Len, unsigned Dim>
03803     const Numeric& ArrayND<Numeric,Len,Dim>::at(
03804         const unsigned i0,
03805         const unsigned i1,
03806         const unsigned i2,
03807         const unsigned i3,
03808         const unsigned i4,
03809         const unsigned i5,
03810         const unsigned i6,
03811         const unsigned i7,
03812         const unsigned i8) const 
03813     {
03814         if (9U != dim_) throw npstat::NpstatInvalidArgument(
03815             "In npstat::ArrayND::at: wrong # of args (not rank 9 array)");
03816         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03817             "In npstat::ArrayND::at: index 0 out of range (rank 9)");
03818         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03819             "In npstat::ArrayND::at: index 1 out of range (rank 9)");
03820         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
03821             "In npstat::ArrayND::at: index 2 out of range (rank 9)");
03822         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
03823             "In npstat::ArrayND::at: index 3 out of range (rank 9)");
03824         if (i4 >= shape_[4]) throw npstat::NpstatOutOfRange(
03825             "In npstat::ArrayND::at: index 4 out of range (rank 9)");
03826         if (i5 >= shape_[5]) throw npstat::NpstatOutOfRange(
03827             "In npstat::ArrayND::at: index 5 out of range (rank 9)");
03828         if (i6 >= shape_[6]) throw npstat::NpstatOutOfRange(
03829             "In npstat::ArrayND::at: index 6 out of range (rank 9)");
03830         if (i7 >= shape_[7]) throw npstat::NpstatOutOfRange(
03831             "In npstat::ArrayND::at: index 7 out of range (rank 9)");
03832         if (i8 >= shape_[8]) throw npstat::NpstatOutOfRange(
03833             "In npstat::ArrayND::at: index 8 out of range (rank 9)");
03834         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03835                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] +
03836                      i6*strides_[6] + i7*strides_[7] + i8];
03837     }
03838 
03839     template<typename Numeric, unsigned Len, unsigned Dim>
03840     const Numeric& ArrayND<Numeric,Len,Dim>::at(
03841         const unsigned i0,
03842         const unsigned i1,
03843         const unsigned i2,
03844         const unsigned i3,
03845         const unsigned i4,
03846         const unsigned i5,
03847         const unsigned i6,
03848         const unsigned i7,
03849         const unsigned i8,
03850         const unsigned i9) const 
03851     {
03852         if (10U != dim_) throw npstat::NpstatInvalidArgument(
03853             "In npstat::ArrayND::at: wrong # of args (not rank 10 array)");
03854         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03855             "In npstat::ArrayND::at: index 0 out of range (rank 10)");
03856         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03857             "In npstat::ArrayND::at: index 1 out of range (rank 10)");
03858         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
03859             "In npstat::ArrayND::at: index 2 out of range (rank 10)");
03860         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
03861             "In npstat::ArrayND::at: index 3 out of range (rank 10)");
03862         if (i4 >= shape_[4]) throw npstat::NpstatOutOfRange(
03863             "In npstat::ArrayND::at: index 4 out of range (rank 10)");
03864         if (i5 >= shape_[5]) throw npstat::NpstatOutOfRange(
03865             "In npstat::ArrayND::at: index 5 out of range (rank 10)");
03866         if (i6 >= shape_[6]) throw npstat::NpstatOutOfRange(
03867             "In npstat::ArrayND::at: index 6 out of range (rank 10)");
03868         if (i7 >= shape_[7]) throw npstat::NpstatOutOfRange(
03869             "In npstat::ArrayND::at: index 7 out of range (rank 10)");
03870         if (i8 >= shape_[8]) throw npstat::NpstatOutOfRange(
03871             "In npstat::ArrayND::at: index 8 out of range (rank 10)");
03872         if (i9 >= shape_[9]) throw npstat::NpstatOutOfRange(
03873             "In npstat::ArrayND::at: index 9 out of range (rank 10)");
03874         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03875                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] +
03876                      i6*strides_[6] + i7*strides_[7] + i8*strides_[8] + i9];
03877     }
03878 
03879     template<typename Numeric, unsigned Len, unsigned Dim>
03880     Numeric& ArrayND<Numeric,Len,Dim>::at(
03881         const unsigned i0,
03882         const unsigned i1,
03883         const unsigned i2)
03884     {
03885         if (3U != dim_) throw npstat::NpstatInvalidArgument(
03886             "In npstat::ArrayND::at: wrong # of args (not rank 3 array)");
03887         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03888             "In npstat::ArrayND::at: index 0 out of range (rank 3)");
03889         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03890             "In npstat::ArrayND::at: index 1 out of range (rank 3)");
03891         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
03892             "In npstat::ArrayND::at: index 2 out of range (rank 3)");
03893         return data_[i0*strides_[0] + i1*strides_[1] + i2];
03894     }
03895 
03896     template<typename Numeric, unsigned Len, unsigned Dim>
03897     Numeric& ArrayND<Numeric,Len,Dim>::at(
03898         const unsigned i0,
03899         const unsigned i1,
03900         const unsigned i2,
03901         const unsigned i3)
03902     {
03903         if (4U != dim_) throw npstat::NpstatInvalidArgument(
03904             "In npstat::ArrayND::at: wrong # of args (not rank 4 array)");
03905         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03906             "In npstat::ArrayND::at: index 0 out of range (rank 4)");
03907         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03908             "In npstat::ArrayND::at: index 1 out of range (rank 4)");
03909         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
03910             "In npstat::ArrayND::at: index 2 out of range (rank 4)");
03911         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
03912             "In npstat::ArrayND::at: index 3 out of range (rank 4)");
03913         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + i3];
03914     }
03915 
03916     template<typename Numeric, unsigned Len, unsigned Dim>
03917     Numeric& ArrayND<Numeric,Len,Dim>::at(
03918         const unsigned i0,
03919         const unsigned i1,
03920         const unsigned i2,
03921         const unsigned i3,
03922         const unsigned i4)
03923     {
03924         if (5U != dim_) throw npstat::NpstatInvalidArgument(
03925             "In npstat::ArrayND::at: wrong # of args (not rank 5 array)");
03926         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03927             "In npstat::ArrayND::at: index 0 out of range (rank 5)");
03928         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03929             "In npstat::ArrayND::at: index 1 out of range (rank 5)");
03930         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
03931             "In npstat::ArrayND::at: index 2 out of range (rank 5)");
03932         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
03933             "In npstat::ArrayND::at: index 3 out of range (rank 5)");
03934         if (i4 >= shape_[4]) throw npstat::NpstatOutOfRange(
03935             "In npstat::ArrayND::at: index 4 out of range (rank 5)");
03936         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03937                      i3*strides_[3] + i4];
03938     }
03939 
03940     template<typename Numeric, unsigned Len, unsigned Dim>
03941     Numeric& ArrayND<Numeric,Len,Dim>::at(
03942         const unsigned i0,
03943         const unsigned i1,
03944         const unsigned i2,
03945         const unsigned i3,
03946         const unsigned i4,
03947         const unsigned i5)
03948     {
03949         if (6U != dim_) throw npstat::NpstatInvalidArgument(
03950             "In npstat::ArrayND::at: wrong # of args (not rank 6 array)");
03951         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03952             "In npstat::ArrayND::at: index 0 out of range (rank 6)");
03953         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03954             "In npstat::ArrayND::at: index 1 out of range (rank 6)");
03955         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
03956             "In npstat::ArrayND::at: index 2 out of range (rank 6)");
03957         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
03958             "In npstat::ArrayND::at: index 3 out of range (rank 6)");
03959         if (i4 >= shape_[4]) throw npstat::NpstatOutOfRange(
03960             "In npstat::ArrayND::at: index 4 out of range (rank 6)");
03961         if (i5 >= shape_[5]) throw npstat::NpstatOutOfRange(
03962             "In npstat::ArrayND::at: index 5 out of range (rank 6)");
03963         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03964                      i3*strides_[3] + i4*strides_[4] + i5];
03965     }
03966 
03967     template<typename Numeric, unsigned Len, unsigned Dim>
03968     Numeric& ArrayND<Numeric,Len,Dim>::at(
03969         const unsigned i0,
03970         const unsigned i1,
03971         const unsigned i2,
03972         const unsigned i3,
03973         const unsigned i4,
03974         const unsigned i5,
03975         const unsigned i6)
03976     {
03977         if (7U != dim_) throw npstat::NpstatInvalidArgument(
03978             "In npstat::ArrayND::at: wrong # of args (not rank 7 array)");
03979         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
03980             "In npstat::ArrayND::at: index 0 out of range (rank 7)");
03981         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
03982             "In npstat::ArrayND::at: index 1 out of range (rank 7)");
03983         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
03984             "In npstat::ArrayND::at: index 2 out of range (rank 7)");
03985         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
03986             "In npstat::ArrayND::at: index 3 out of range (rank 7)");
03987         if (i4 >= shape_[4]) throw npstat::NpstatOutOfRange(
03988             "In npstat::ArrayND::at: index 4 out of range (rank 7)");
03989         if (i5 >= shape_[5]) throw npstat::NpstatOutOfRange(
03990             "In npstat::ArrayND::at: index 5 out of range (rank 7)");
03991         if (i6 >= shape_[6]) throw npstat::NpstatOutOfRange(
03992             "In npstat::ArrayND::at: index 6 out of range (rank 7)");
03993         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
03994                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] + i6];
03995     }
03996 
03997     template<typename Numeric, unsigned Len, unsigned Dim>
03998     Numeric& ArrayND<Numeric,Len,Dim>::at(
03999         const unsigned i0,
04000         const unsigned i1,
04001         const unsigned i2,
04002         const unsigned i3,
04003         const unsigned i4,
04004         const unsigned i5,
04005         const unsigned i6,
04006         const unsigned i7)
04007     {
04008         if (8U != dim_) throw npstat::NpstatInvalidArgument(
04009             "In npstat::ArrayND::at: wrong # of args (not rank 8 array)");
04010         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
04011             "In npstat::ArrayND::at: index 0 out of range (rank 8)");
04012         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
04013             "In npstat::ArrayND::at: index 1 out of range (rank 8)");
04014         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
04015             "In npstat::ArrayND::at: index 2 out of range (rank 8)");
04016         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
04017             "In npstat::ArrayND::at: index 3 out of range (rank 8)");
04018         if (i4 >= shape_[4]) throw npstat::NpstatOutOfRange(
04019             "In npstat::ArrayND::at: index 4 out of range (rank 8)");
04020         if (i5 >= shape_[5]) throw npstat::NpstatOutOfRange(
04021             "In npstat::ArrayND::at: index 5 out of range (rank 8)");
04022         if (i6 >= shape_[6]) throw npstat::NpstatOutOfRange(
04023             "In npstat::ArrayND::at: index 6 out of range (rank 8)");
04024         if (i7 >= shape_[7]) throw npstat::NpstatOutOfRange(
04025             "In npstat::ArrayND::at: index 7 out of range (rank 8)");
04026         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
04027                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] +
04028                      i6*strides_[6] + i7];
04029     }
04030 
04031     template<typename Numeric, unsigned Len, unsigned Dim>
04032     Numeric& ArrayND<Numeric,Len,Dim>::at(
04033         const unsigned i0,
04034         const unsigned i1,
04035         const unsigned i2,
04036         const unsigned i3,
04037         const unsigned i4,
04038         const unsigned i5,
04039         const unsigned i6,
04040         const unsigned i7,
04041         const unsigned i8)
04042     {
04043         if (9U != dim_) throw npstat::NpstatInvalidArgument(
04044             "In npstat::ArrayND::at: wrong # of args (not rank 9 array)");
04045         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
04046             "In npstat::ArrayND::at: index 0 out of range (rank 9)");
04047         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
04048             "In npstat::ArrayND::at: index 1 out of range (rank 9)");
04049         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
04050             "In npstat::ArrayND::at: index 2 out of range (rank 9)");
04051         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
04052             "In npstat::ArrayND::at: index 3 out of range (rank 9)");
04053         if (i4 >= shape_[4]) throw npstat::NpstatOutOfRange(
04054             "In npstat::ArrayND::at: index 4 out of range (rank 9)");
04055         if (i5 >= shape_[5]) throw npstat::NpstatOutOfRange(
04056             "In npstat::ArrayND::at: index 5 out of range (rank 9)");
04057         if (i6 >= shape_[6]) throw npstat::NpstatOutOfRange(
04058             "In npstat::ArrayND::at: index 6 out of range (rank 9)");
04059         if (i7 >= shape_[7]) throw npstat::NpstatOutOfRange(
04060             "In npstat::ArrayND::at: index 7 out of range (rank 9)");
04061         if (i8 >= shape_[8]) throw npstat::NpstatOutOfRange(
04062             "In npstat::ArrayND::at: index 8 out of range (rank 9)");
04063         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
04064                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] +
04065                      i6*strides_[6] + i7*strides_[7] + i8];
04066     }
04067 
04068     template<typename Numeric, unsigned Len, unsigned Dim>
04069     Numeric& ArrayND<Numeric,Len,Dim>::at(
04070         const unsigned i0,
04071         const unsigned i1,
04072         const unsigned i2,
04073         const unsigned i3,
04074         const unsigned i4,
04075         const unsigned i5,
04076         const unsigned i6,
04077         const unsigned i7,
04078         const unsigned i8,
04079         const unsigned i9)
04080     {
04081         if (10U != dim_) throw npstat::NpstatInvalidArgument(
04082             "In npstat::ArrayND::at: wrong # of args (not rank 10 array)");
04083         if (i0 >= shape_[0]) throw npstat::NpstatOutOfRange(
04084             "In npstat::ArrayND::at: index 0 out of range (rank 10)");
04085         if (i1 >= shape_[1]) throw npstat::NpstatOutOfRange(
04086             "In npstat::ArrayND::at: index 1 out of range (rank 10)");
04087         if (i2 >= shape_[2]) throw npstat::NpstatOutOfRange(
04088             "In npstat::ArrayND::at: index 2 out of range (rank 10)");
04089         if (i3 >= shape_[3]) throw npstat::NpstatOutOfRange(
04090             "In npstat::ArrayND::at: index 3 out of range (rank 10)");
04091         if (i4 >= shape_[4]) throw npstat::NpstatOutOfRange(
04092             "In npstat::ArrayND::at: index 4 out of range (rank 10)");
04093         if (i5 >= shape_[5]) throw npstat::NpstatOutOfRange(
04094             "In npstat::ArrayND::at: index 5 out of range (rank 10)");
04095         if (i6 >= shape_[6]) throw npstat::NpstatOutOfRange(
04096             "In npstat::ArrayND::at: index 6 out of range (rank 10)");
04097         if (i7 >= shape_[7]) throw npstat::NpstatOutOfRange(
04098             "In npstat::ArrayND::at: index 7 out of range (rank 10)");
04099         if (i8 >= shape_[8]) throw npstat::NpstatOutOfRange(
04100             "In npstat::ArrayND::at: index 8 out of range (rank 10)");
04101         if (i9 >= shape_[9]) throw npstat::NpstatOutOfRange(
04102             "In npstat::ArrayND::at: index 9 out of range (rank 10)");
04103         return data_[i0*strides_[0] + i1*strides_[1] + i2*strides_[2] + 
04104                      i3*strides_[3] + i4*strides_[4] + i5*strides_[5] +
04105                      i6*strides_[6] + i7*strides_[7] + i8*strides_[8] + i9];
04106     }
04107 
04108     template<typename Numeric, unsigned Len, unsigned Dim>
04109     template<unsigned Len2, unsigned Dim2>
04110     double ArrayND<Numeric,Len,Dim>::maxAbsDifference(
04111         const ArrayND<Numeric,Len2,Dim2>& r) const
04112     {
04113         if (!isShapeCompatible(r)) throw npstat::NpstatInvalidArgument(
04114             "In npstat::ArrayND::maxAbsDifference: "
04115             "incompatible argument array shape");
04116         if (dim_)
04117         {
04118             double maxd = 0.0;
04119             for (unsigned long i=0; i<len_; ++i)
04120             {
04121                 const Numeric rval = r.data_[i];
04122                 const double d = absDifference(data_[i], rval);
04123                 if (d > maxd)
04124                     maxd = d;
04125             }
04126             return maxd;
04127         }
04128         else
04129         {
04130             const Numeric rval = r.localData_[0];
04131             return absDifference(localData_[0], rval);
04132         }
04133     }
04134 
04135     template<typename Numeric, unsigned Len, unsigned Dim>
04136     template<unsigned Len2, unsigned Dim2>
04137     bool ArrayND<Numeric,Len,Dim>::operator==(
04138         const ArrayND<Numeric,Len2,Dim2>& r) const
04139     {
04140         if (shapeIsKnown_ != r.shapeIsKnown_)
04141             return false;
04142         if (r.dim_ != dim_)
04143             return false;
04144         if (r.len_ != len_)
04145             return false;
04146         for (unsigned i=0; i<dim_; ++i)
04147             if (shape_[i] != r.shape_[i])
04148                 return false;
04149         for (unsigned i=0; i<dim_; ++i)
04150             assert(strides_[i] == r.strides_[i]);
04151         for (unsigned long j=0; j<len_; ++j)
04152             if (data_[j] != r.data_[j])
04153                 return false;
04154         return true;
04155     }
04156 
04157     template<typename Numeric, unsigned Len, unsigned Dim>
04158     template<unsigned Len2, unsigned Dim2>
04159     inline bool ArrayND<Numeric,Len,Dim>::operator!=(
04160         const ArrayND<Numeric,Len2,Dim2>& r) const
04161     {
04162         return !(*this == r);
04163     }
04164 
04165     template<typename Numeric, unsigned Len, unsigned Dim>
04166     template<typename Num2>
04167     ArrayND<Numeric,Len,Dim>
04168     ArrayND<Numeric,Len,Dim>::operator*(const Num2& r) const
04169     {
04170         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04171             "Initialize npstat::ArrayND before calling method \"operator*\"");
04172         ArrayND<Numeric,Len,Dim> result(shape_, dim_);
04173         for (unsigned long i=0; i<len_; ++i)
04174             result.data_[i] = data_[i]*r;
04175         return result;
04176     }
04177 
04178     template<typename Numeric, unsigned Len, unsigned Dim>
04179     template<typename Num2>
04180     ArrayND<Numeric,Len,Dim>
04181     ArrayND<Numeric,Len,Dim>::operator/(const Num2& r) const
04182     {
04183         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04184             "Initialize npstat::ArrayND before calling method \"operator/\"");
04185         if (r == Num2()) throw npstat::NpstatRuntimeError(
04186             "In npstat::ArrayND::operator/: division by zero");
04187         ArrayND<Numeric,Len,Dim> result(shape_, dim_);
04188         for (unsigned long i=0; i<len_; ++i)
04189             result.data_[i] = data_[i]/r;
04190         return result;
04191     }
04192 
04193     template<typename Numeric, unsigned Len, unsigned Dim>
04194     template <unsigned Len2, unsigned Dim2>
04195     ArrayND<Numeric,Len,Dim>
04196     ArrayND<Numeric,Len,Dim>::operator+(
04197         const ArrayND<Numeric,Len2,Dim2>& r) const
04198     {
04199         if (!isShapeCompatible(r)) throw npstat::NpstatInvalidArgument(
04200             "In npstat::ArrayND::operator+: "
04201             "incompatible argument array shape");
04202         ArrayND<Numeric,Len,Dim> result(shape_, dim_);
04203         for (unsigned long i=0; i<len_; ++i)
04204             result.data_[i] = data_[i] + r.data_[i];
04205         return result;
04206     }
04207 
04208     template<typename Numeric, unsigned Len, unsigned Dim>
04209     template <unsigned Len2, unsigned Dim2>
04210     ArrayND<Numeric,Len,Dim>
04211     ArrayND<Numeric,Len,Dim>::operator-(
04212         const ArrayND<Numeric,Len2,Dim2>& r) const
04213     {
04214         if (!isShapeCompatible(r)) throw npstat::NpstatInvalidArgument(
04215             "In npstat::ArrayND::operator-: "
04216             "incompatible argument array shape");
04217         ArrayND<Numeric,Len,Dim> result(shape_, dim_);
04218         for (unsigned long i=0; i<len_; ++i)
04219             result.data_[i] = data_[i] - r.data_[i];
04220         return result;
04221     }
04222 
04223     template<typename Numeric, unsigned Len, unsigned Dim>
04224     inline ArrayND<Numeric,Len,Dim> ArrayND<Numeric,Len,Dim>::operator+() const
04225     {
04226         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04227             "Initialize npstat::ArrayND before calling method \"operator+\"");
04228         return *this;
04229     }
04230 
04231     template<typename Numeric, unsigned Len, unsigned Dim>
04232     ArrayND<Numeric,Len,Dim> ArrayND<Numeric,Len,Dim>::operator-() const
04233     {
04234         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04235             "Initialize npstat::ArrayND before calling method \"operator-\"");
04236         ArrayND<Numeric,Len,Dim> result(shape_, dim_);
04237         for (unsigned long i=0; i<len_; ++i)
04238             result.data_[i] = -data_[i];
04239         return result;
04240     }
04241 
04242     template<typename Numeric, unsigned Len, unsigned Dim>
04243     template <typename Num2>
04244     ArrayND<Numeric,Len,Dim>&
04245     ArrayND<Numeric,Len,Dim>::operator*=(const Num2& r)
04246     {
04247         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04248             "Initialize npstat::ArrayND before calling method \"operator*=\"");
04249         for (unsigned long i=0; i<len_; ++i)
04250             data_[i] *= r;
04251         return *this;
04252     }
04253 
04254     template<typename Numeric, unsigned Len, unsigned Dim>
04255     ArrayND<Numeric,Len,Dim>&
04256     ArrayND<Numeric,Len,Dim>::makeNonNegative()
04257     {
04258         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04259             "Initialize npstat::ArrayND before calling method \"makeNonNegative\"");
04260         const Numeric zero = Numeric();
04261         if (dim_)
04262         {
04263             for (unsigned long i=0; i<len_; ++i)
04264                 if (!(ComplexComparesAbs<Numeric>::more(data_[i], zero)))
04265                     data_[i] = zero;
04266         }
04267         else
04268             if (!(ComplexComparesAbs<Numeric>::more(localData_[0], zero)))
04269                 localData_[0] = zero;
04270         return *this;
04271     }
04272 
04273     template<typename Numeric, unsigned Len, unsigned Dim>
04274     unsigned ArrayND<Numeric,Len,Dim>::makeCopulaSteps(
04275         const double tolerance, const unsigned nCycles)
04276     {
04277         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04278             "Initialize npstat::ArrayND before calling method \"makeCopulaSteps\"");
04279         if (nCycles == 0U)
04280             return 0U;
04281         if (!dim_) throw npstat::NpstatInvalidArgument(
04282             "npstat::ArrayND::makeCopulaSteps method "
04283             "can not be used with array of 0 rank");
04284 
04285         const Numeric zero = Numeric();
04286         for (unsigned long i=0; i<len_; ++i)
04287             if (!(ComplexComparesAbs<Numeric>::more(data_[i], zero)))
04288                 data_[i] = zero;
04289 
04290         std::vector<Numeric*> axesPtrBuf(dim_);
04291         Numeric** axes = &axesPtrBuf[0];
04292         const Numeric one = static_cast<Numeric>(1);
04293 
04294         // Memory for the axis accumulators
04295         unsigned idxSum = 0;
04296         for (unsigned i=0; i<dim_; ++i)
04297             idxSum += shape_[i];
04298         std::vector<Numeric> axesBuf(idxSum);
04299         axes[0] = &axesBuf[0];
04300         for (unsigned i=1; i<dim_; ++i)
04301             axes[i] = axes[i-1] + shape_[i-1];
04302 
04303         // Accumulate axis projections
04304         unsigned icycle = 0;
04305         for (; icycle<nCycles; ++icycle)
04306         {
04307             for (unsigned i=0; i<idxSum; ++i)
04308                 axesBuf[i] = zero;
04309 
04310             // Accumulate sums for each axis
04311             for (unsigned long idat=0; idat<len_; ++idat)
04312             {
04313                 unsigned long l = idat;
04314                 for (unsigned i=0; i<dim_; ++i)
04315                 {
04316                     const unsigned idx = l / strides_[i];
04317                     l -= (idx * strides_[i]);
04318                     axes[i][idx] += data_[idat];
04319                 }
04320             }
04321 
04322             // Make averages out of sums
04323             bool withinTolerance = true;
04324             Numeric totalSum = zero;
04325             for (unsigned i=0; i<dim_; ++i)
04326             {
04327                 Numeric axisSum = zero;
04328                 const unsigned amax = shape_[i];
04329                 for (unsigned a=0; a<amax; ++a)
04330                 {
04331                     if (axes[i][a] == zero)
04332                         throw npstat::NpstatRuntimeError(
04333                             "In npstat::ArrayND::makeCopulaSteps: "
04334                             "marginal density is zero");
04335                     axisSum += axes[i][a];
04336                 }
04337                 totalSum += axisSum;
04338                 const Numeric axisAverage = axisSum/static_cast<Numeric>(amax);
04339                 for (unsigned a=0; a<amax; ++a)
04340                     axes[i][a] /= axisAverage;
04341                 for (unsigned a=0; a<amax && withinTolerance; ++a)
04342                 {
04343                     const double adelta = absDifference(axes[i][a], one);
04344                     if (adelta > tolerance)
04345                         withinTolerance = false;
04346                 }
04347             }
04348 
04349             if (withinTolerance)
04350                 break;
04351 
04352             const Numeric totalAverage = totalSum/
04353                 static_cast<Numeric>(len_)/static_cast<Numeric>(dim_);
04354 
04355             // Run over all points again and divide by
04356             // the product of marginals
04357             for (unsigned long idat=0; idat<len_; ++idat)
04358             {
04359                 unsigned long l = idat;
04360                 for (unsigned i=0; i<dim_; ++i)
04361                 {
04362                     const unsigned idx = l / strides_[i];
04363                     l -= (idx * strides_[i]);
04364                     data_[idat] /= axes[i][idx];
04365                 }
04366                 data_[idat] /= totalAverage;
04367             }
04368         }
04369 
04370         return icycle;
04371     }
04372 
04373     template<typename Numeric, unsigned Len, unsigned Dim>
04374     template <typename Num2>
04375     ArrayND<Numeric,Len,Dim>&
04376     ArrayND<Numeric,Len,Dim>::operator/=(const Num2& r)
04377     {
04378         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04379             "Initialize npstat::ArrayND before calling method \"operator/=\"");
04380         if (r == Num2()) throw npstat::NpstatRuntimeError(
04381             "In npstat::ArrayND::operator/=: division by zero");
04382         for (unsigned long i=0; i<len_; ++i)
04383             data_[i] /= r;
04384         return *this;
04385     }
04386 
04387     template<typename Numeric, unsigned Len, unsigned Dim>
04388     template <typename Num2, unsigned Len2, unsigned Dim2>
04389     ArrayND<Numeric,Len,Dim>&
04390     ArrayND<Numeric,Len,Dim>::operator+=(const ArrayND<Num2,Len2,Dim2>& r)
04391     {
04392         if (!isShapeCompatible(r)) throw npstat::NpstatInvalidArgument(
04393             "In npstat::ArrayND::operator+=: "
04394             "incompatible argument array shape");
04395         for (unsigned long i=0; i<len_; ++i)
04396             data_[i] += r.data_[i];
04397         return *this;
04398     }
04399 
04400     template<typename Numeric, unsigned Len, unsigned Dim>
04401     template <typename Num3, typename Num2, unsigned Len2, unsigned Dim2>
04402     ArrayND<Numeric,Len,Dim>&
04403     ArrayND<Numeric,Len,Dim>::addmul(const ArrayND<Num2,Len2,Dim2>& r,
04404                                      const Num3& c)
04405     {
04406         if (!isShapeCompatible(r)) throw npstat::NpstatInvalidArgument(
04407             "In npstat::ArrayND::addmul: "
04408             "incompatible argument array shape");
04409         for (unsigned long i=0; i<len_; ++i)
04410             data_[i] += r.data_[i]*c;
04411         return *this;
04412     }
04413 
04414     template<typename Numeric, unsigned Len, unsigned Dim>
04415     template <typename Num2, unsigned Len2, unsigned Dim2>
04416     ArrayND<Numeric,Len,Dim>&
04417     ArrayND<Numeric,Len,Dim>::operator-=(const ArrayND<Num2,Len2,Dim2>& r)
04418     {
04419         if (!isShapeCompatible(r)) throw npstat::NpstatInvalidArgument(
04420             "In npstat::ArrayND::operator-=: "
04421             "incompatible argument array shape");
04422         for (unsigned long i=0; i<len_; ++i)
04423             data_[i] -= r.data_[i];
04424         return *this;
04425     }
04426 
04427     template<typename Numeric, unsigned Len, unsigned Dim>
04428     Numeric ArrayND<Numeric,Len,Dim>::interpolate1(
04429         const double *coords, const unsigned dim) const
04430     {
04431         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04432             "Initialize npstat::ArrayND before calling method \"interpolate1\"");
04433         if (dim != dim_) throw npstat::NpstatInvalidArgument(
04434             "In npstat::ArrayND::interpolate1: incompatible coordinate length");
04435         if (dim)
04436         {
04437             const unsigned maxdim = CHAR_BIT*sizeof(unsigned long);
04438             if (dim_ >= maxdim)
04439                 throw npstat::NpstatInvalidArgument(
04440                     "In npstat::ArrayND::interpolate1: array rank is too large");
04441 
04442             double dx[maxdim];
04443             unsigned ix[maxdim];
04444             for (unsigned i=0; i<dim; ++i)
04445             {
04446                 const double x = coords[i];
04447                 if (x <= 0.0)
04448                 {
04449                     ix[i] = 0;
04450                     dx[i] = 0.0;
04451                 }
04452                 else if (x >= static_cast<double>(shape_[i] - 1))
04453                 {
04454                     ix[i] = shape_[i] - 1;
04455                     dx[i] = 0.0;
04456                 }
04457                 else
04458                 {
04459                     ix[i] = static_cast<unsigned>(std::floor(x));
04460                     dx[i] = x - ix[i];
04461                 }
04462             }
04463 
04464             Numeric sum = Numeric();
04465             const unsigned long maxcycle = 1UL << dim;
04466             for (unsigned long icycle=0UL; icycle<maxcycle; ++icycle)
04467             {
04468                 double w = 1.0;
04469                 unsigned long icell = 0UL;
04470                 for (unsigned i=0; i<dim; ++i)
04471                 {
04472                     if (icycle & (1UL << i))
04473                     {
04474                         w *= dx[i];
04475                         icell += strides_[i]*(ix[i] + 1U);
04476                     }
04477                     else
04478                     {
04479                         w *= (1.0 - dx[i]);
04480                         icell += strides_[i]*ix[i];
04481                     }
04482                 }
04483                 if (w > 0.0)
04484                     sum += data_[icell]*static_cast<proper_double>(w);
04485             }
04486             return sum;
04487         }
04488         else
04489             return localData_[0];
04490     }
04491 
04492     template<typename Numeric, unsigned Len, unsigned Dim>
04493     Numeric ArrayND<Numeric,Len,Dim>::interpolateLoop(
04494         const unsigned level, const double* coords, const Numeric* base) const
04495     {
04496         const unsigned npoints = shape_[level];
04497         const double x = coords[level];
04498 
04499         unsigned ix, npt = 1;
04500         double dx = 0.0;
04501         if (x < 0.0)
04502             ix = 0;
04503         else if (x > static_cast<double>(npoints - 1))
04504             ix = npoints - 1;
04505         else
04506         {
04507             ix = static_cast<unsigned>(std::floor(x));
04508             if (ix) --ix;
04509             unsigned imax = ix + 3;
04510             while (imax >= npoints)
04511             {
04512                 if (ix) --ix;
04513                 --imax;
04514             }
04515             dx = x - ix;
04516             npt = imax + 1 - ix;
04517         }
04518         assert(npt >= 1 && npt <= 4);
04519 
04520         Numeric fit[4];
04521         if (level < dim_ - 1)
04522             for (unsigned ipt=0; ipt<npt; ++ipt)
04523                 fit[ipt] = interpolateLoop(level + 1, coords,
04524                                            base + (ix + ipt)*strides_[level]);
04525 
04526         const Numeric* const v = (level == dim_ - 1 ? base + ix : fit);
04527         switch (npt)
04528         {
04529         case 1:
04530             return v[0];
04531         case 2:
04532             return interpolate_linear(dx, v[0], v[1]);
04533         case 3:
04534             return interpolate_quadratic(dx, v[0], v[1], v[2]);
04535         case 4:
04536             return interpolate_cubic(dx, v[0], v[1], v[2], v[3]);
04537         default:
04538             assert(0);
04539             return Numeric();
04540         }
04541     }
04542 
04543     template<typename Numeric, unsigned Len, unsigned Dim>
04544     inline Numeric ArrayND<Numeric,Len,Dim>::interpolate3(
04545         const double* coords, const unsigned dim) const
04546     {
04547         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04548             "Initialize npstat::ArrayND before calling method \"interpolate3\"");
04549         if (dim != dim_) throw npstat::NpstatInvalidArgument(
04550             "In npstat::ArrayND::interpolate3: incompatible coordinate length");
04551         if (dim)
04552         {
04553             assert(coords);
04554             return interpolateLoop(0, coords, data_);
04555         }
04556         else
04557             return localData_[0];
04558     }
04559 
04560     template<typename Numeric, unsigned Len, unsigned Dim>
04561     template<class Functor>
04562     ArrayND<Numeric,Len,Dim>& ArrayND<Numeric,Len,Dim>::apply(Functor f)
04563     {
04564         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04565             "Initialize npstat::ArrayND before calling method \"apply\"");
04566         for (unsigned long i=0; i<len_; ++i)
04567             data_[i] = static_cast<Numeric>(f(data_[i]));
04568         return *this;
04569     }
04570 
04571     template<typename Numeric, unsigned Len, unsigned Dim>
04572     template<class Functor>
04573     ArrayND<Numeric,Len,Dim>& ArrayND<Numeric,Len,Dim>::scanInPlace(
04574         Functor f)
04575     {
04576         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04577             "Initialize npstat::ArrayND before calling method \"scanInPlace\"");
04578         for (unsigned long i=0; i<len_; ++i)
04579             f(data_[i]);
04580         return *this;
04581     }
04582 
04583     template<typename Numeric, unsigned Len, unsigned Dim>
04584     ArrayND<Numeric,Len,Dim>& ArrayND<Numeric,Len,Dim>::constFill(
04585         const Numeric c)
04586     {
04587         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04588             "Initialize npstat::ArrayND before calling method \"constFill\"");
04589         for (unsigned long i=0; i<len_; ++i)
04590             data_[i] = c;
04591         return *this;
04592     }
04593 
04594     template<typename Numeric, unsigned Len, unsigned Dim>
04595     inline ArrayND<Numeric,Len,Dim>& ArrayND<Numeric,Len,Dim>::clear()
04596     {
04597         return constFill(Numeric());
04598     }
04599 
04600     template<typename Numeric, unsigned Len, unsigned Dim>
04601     ArrayND<Numeric,Len,Dim>& ArrayND<Numeric,Len,Dim>::uninitialize()
04602     {
04603         destroyBuffer(data_, localData_);
04604         destroyBuffer(strides_, localStrides_);
04605         destroyBuffer(shape_, localShape_);
04606         localData_[0] = Numeric();
04607         data_ = localData_;
04608         strides_ = 0;
04609         shape_ = 0;
04610         len_ = 0;
04611         dim_ = 0;
04612         shapeIsKnown_ = false;
04613         return *this;
04614     }
04615 
04616     template<typename Numeric, unsigned Len, unsigned Dim>
04617     ArrayND<Numeric,Len,Dim>& ArrayND<Numeric,Len,Dim>::makeUnit()
04618     {
04619         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04620             "Initialize npstat::ArrayND before calling method \"makeUnit\"");
04621         if (dim_ < 2) throw npstat::NpstatInvalidArgument(
04622             "npstat::ArrayND::makeUnit method "
04623             "can not be used with arrays of rank less than 2");
04624         constFill(Numeric());
04625         unsigned long stride = 0UL;
04626         const unsigned dimlen = shape_[0];
04627         for (unsigned i=0; i<dim_; ++i)
04628         {
04629             if (shape_[i] != dimlen) throw npstat::NpstatInvalidArgument(
04630                 "npstat::ArrayND::makeUnit method needs "
04631                 "the array span to be the same in ech dimension");
04632             stride += strides_[i];
04633         }
04634         const Numeric one(static_cast<Numeric>(1));
04635         for (unsigned i=0; i<dimlen; ++i)
04636             data_[i*stride] = one;
04637         return *this;
04638     }
04639 
04640     template<typename Numeric, unsigned Len, unsigned Dim>
04641     void ArrayND<Numeric,Len,Dim>::linearFillLoop(
04642         const unsigned level, const double s0, const unsigned long idx,
04643         const double shift, const double* coeffs)
04644     {
04645         const unsigned imax = shape_[level];
04646         const double c = coeffs[level];
04647         if (level == dim_ - 1)
04648         {
04649             Numeric* d = &data_[idx];
04650             for (unsigned i=0; i<imax; ++i)
04651             {
04652                 // Note that we want to add "shift" only at the
04653                 // very end. This might improve the numerical
04654                 // precision of the result.
04655                 const double sum = s0 + c*i + shift;
04656                 d[i] = static_cast<Numeric>(sum);
04657             }
04658         }
04659         else
04660         {
04661             const unsigned long stride = strides_[level];
04662             for (unsigned i=0; i<imax; ++i)
04663                 linearFillLoop(level+1, s0 + c*i, idx + i*stride,
04664                                shift, coeffs);
04665         }
04666     }
04667 
04668     template<typename Numeric, unsigned Len, unsigned Dim>
04669     ArrayND<Numeric,Len,Dim>& ArrayND<Numeric,Len,Dim>::linearFill(
04670         const double* coeffs, const unsigned dimCoeffs, const double shift)
04671     {
04672         // Make sure the object has been initialized
04673         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04674             "Initialize npstat::ArrayND before calling method \"linearFill\"");
04675         if (dim_ != dimCoeffs) throw npstat::NpstatInvalidArgument(
04676             "In npstat::ArrayND::linearFill: incompatible number of coefficients");
04677         if (dim_)
04678         {
04679             assert(coeffs);
04680             linearFillLoop(0U, 0.0, 0UL, shift, coeffs);
04681         }
04682         else
04683             localData_[0] = static_cast<Numeric>(shift);
04684         return *this;
04685     }
04686 
04687     template<typename Numeric, unsigned Len, unsigned Dim>
04688     template<class Functor>
04689     void ArrayND<Numeric,Len,Dim>::functorFillLoop(
04690         const unsigned level, const unsigned long idx,
04691         Functor f, unsigned* farg)
04692     {
04693         const unsigned imax = shape_[level];
04694         if (level == dim_ - 1)
04695         {
04696             Numeric* d = &data_[idx];
04697             const unsigned* myarg = farg;
04698             for (unsigned i = 0; i<imax; ++i)
04699             {
04700                 farg[level] = i;
04701                 d[i] = static_cast<Numeric>(f(myarg, dim_));
04702             }
04703         }
04704         else
04705         {
04706             const unsigned long stride = strides_[level];
04707             for (unsigned i = 0; i<imax; ++i)
04708             {
04709                 farg[level] = i;
04710                 functorFillLoop(level+1, idx + i*stride, f, farg);
04711             }
04712         }
04713     }
04714 
04715     template<typename Numeric, unsigned Len, unsigned Dim>
04716     template <typename Accumulator>
04717     void ArrayND<Numeric,Len,Dim>::convertToLastDimCdfLoop(
04718         ArrayND* sumSlice, const unsigned level, unsigned long idx0,
04719         unsigned long idxSlice, const bool useTrapezoids)
04720     {
04721         static const proper_double half = 0.5;
04722         const unsigned imax = shape_[level];
04723         if (level == dim_ - 1)
04724         {
04725             Accumulator acc = Accumulator();
04726             Numeric* data = data_ + idx0;
04727             if (useTrapezoids)
04728             {
04729                 Numeric oldval = Numeric();
04730                 for (unsigned i = 0; i<imax; ++i)
04731                 {
04732                     acc += (data[i] + oldval)*half;
04733                     oldval = data[i];
04734                     data[i] = static_cast<Numeric>(acc);
04735                 }
04736                 acc += oldval*half;
04737             }
04738             else
04739                 for (unsigned i = 0; i<imax; ++i)
04740                 {
04741                     acc += data[i];
04742                     data[i] = static_cast<Numeric>(acc);
04743                 }
04744             if (sumSlice->dim_)
04745                 sumSlice->data_[idxSlice] = static_cast<Numeric>(acc);
04746             else
04747                 sumSlice->localData_[0] = static_cast<Numeric>(acc);
04748         }
04749         else
04750         {
04751             const unsigned long stride = strides_[level];
04752             unsigned long sumStride = 0UL;
04753             if (sumSlice->dim_)
04754                 sumStride = sumSlice->strides_[level];
04755             for (unsigned i = 0; i<imax; ++i)
04756             {
04757                 convertToLastDimCdfLoop<Accumulator>(
04758                     sumSlice, level+1, idx0, idxSlice, useTrapezoids);
04759                 idx0 += stride;
04760                 idxSlice += sumStride;
04761             }
04762         }
04763     }
04764 
04765     template<typename Numeric, unsigned Len, unsigned Dim>
04766     template <typename Accumulator>
04767     inline void ArrayND<Numeric,Len,Dim>::convertToLastDimCdf(
04768         ArrayND* sumSlice, const bool useTrapezoids)
04769     {
04770         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04771             "Initialize npstat::ArrayND before calling "
04772             "method \"convertToLastDimCdf\"");
04773         if (!dim_) throw npstat::NpstatInvalidArgument(
04774             "npstat::ArrayND::convertToLastDimCdf method "
04775             "can not be used with array of 0 rank");
04776         assert(sumSlice);
04777         if (!sumSlice->shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04778             "In npstat::ArrayND::convertToLastDimCdf: "
04779             "uninitialized argument array");
04780         convertToLastDimCdfLoop<Accumulator>(sumSlice, 0U, 0UL, 0UL,
04781                                              useTrapezoids);
04782     }
04783 
04784     template<typename Numeric, unsigned Len, unsigned Dim>
04785     template<class Functor>
04786     ArrayND<Numeric,Len,Dim>& ArrayND<Numeric,Len,Dim>::functorFill(Functor f)
04787     {
04788         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04789             "Initialize npstat::ArrayND before calling method \"functorFill\"");
04790         if (dim_)
04791         {
04792             unsigned localIndex[Dim];
04793             unsigned* index = makeBuffer(dim_, localIndex, Dim);
04794             functorFillLoop(0U, 0UL, f, index);
04795             destroyBuffer(index, localIndex);
04796         }
04797         else
04798             localData_[0] = static_cast<Numeric>(
04799                 f(static_cast<unsigned*>(0), 0U));
04800         return *this;
04801     }
04802 
04803     template<typename Numeric, unsigned Len, unsigned Dim>
04804     template <typename Num2, unsigned Len2, unsigned Dim2>
04805     bool ArrayND<Numeric,Len,Dim>::isClose(
04806         const ArrayND<Num2,Len2,Dim2>& r, const double eps) const
04807     {
04808         if (eps < 0.0) throw npstat::NpstatDomainError(
04809             "In npstat::ArrayND::isClose: tolerance must not be negative");
04810         if (!isShapeCompatible(r)) throw npstat::NpstatInvalidArgument(
04811             "In npstat::ArrayND::isClose: incompatible argument array shape");
04812         if (dim_)
04813         {
04814             for (unsigned long i=0; i<len_; ++i)
04815             {
04816                 const Numeric rval = r.data_[i];
04817                 if (static_cast<double>(absDifference(data_[i], rval)) > eps)
04818                     return false;
04819             }
04820         }
04821         else
04822         {
04823             const Numeric rval = r.localData_[0];
04824             if (static_cast<double>(absDifference(localData_[0], rval)) > eps)
04825                 return false;
04826         }
04827         return true;
04828     }
04829 
04830     template<typename Numeric, unsigned Len, unsigned Dim>
04831     template<typename Num2, unsigned Len2, unsigned Dim2>
04832     ArrayND<Numeric,Len,Dim> ArrayND<Numeric,Len,Dim>::outer(
04833         const ArrayND<Num2,Len2,Dim2>& r) const
04834     {
04835         return ArrayND<Numeric,Len,Dim>(*this, r);
04836     }
04837 
04838     template<typename Numeric, unsigned Len, unsigned Dim>
04839     void ArrayND<Numeric,Len,Dim>::contractLoop(
04840         unsigned thisLevel, const unsigned resLevel,
04841         const unsigned pos1, const unsigned pos2,
04842         unsigned long idxThis, unsigned long idxRes, ArrayND& result) const
04843     {
04844         while (thisLevel == pos1 || thisLevel == pos2)
04845             ++thisLevel;
04846         assert(thisLevel < dim_);
04847 
04848         if (resLevel == result.dim_ - 1)
04849         {
04850             const unsigned ncontract = shape_[pos1];
04851             const unsigned imax = result.shape_[resLevel];
04852             const unsigned long stride = strides_[pos1] + strides_[pos2];
04853             for (unsigned i=0; i<imax; ++i)
04854             {
04855                 const Numeric* tmp = data_ + (idxThis + i*strides_[thisLevel]);
04856                 Numeric sum = Numeric();
04857                 for (unsigned j=0; j<ncontract; ++j)
04858                     sum += tmp[j*stride];
04859                 result.data_[idxRes + i] = sum;
04860             }
04861         }
04862         else
04863         {
04864             const unsigned imax = result.shape_[resLevel];
04865             assert(imax == shape_[thisLevel]);
04866             for (unsigned i=0; i<imax; ++i)
04867             {
04868                 contractLoop(thisLevel+1, resLevel+1, pos1, pos2,
04869                              idxThis, idxRes, result);
04870                 idxThis += strides_[thisLevel];
04871                 idxRes += result.strides_[resLevel];
04872             }
04873         }
04874     }
04875 
04876     template<typename Numeric, unsigned Len, unsigned Dim>
04877     ArrayND<Numeric,Len,Dim> ArrayND<Numeric,Len,Dim>::contract(
04878         const unsigned pos1, const unsigned pos2) const
04879     {
04880         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04881             "Initialize npstat::ArrayND before calling method \"contract\"");
04882         if (!(pos1 < dim_ && pos2 < dim_ && pos1 != pos2))
04883             throw npstat::NpstatInvalidArgument("In npstat::ArrayND::contract: "
04884                                         "incompatible contraction indices");
04885         if (shape_[pos1] != shape_[pos2])
04886             throw npstat::NpstatInvalidArgument(
04887                 "In npstat::ArrayND::contract: incompatible "
04888                 "length of contracted dimensions");
04889 
04890         // Construct the new shape
04891         unsigned newshapeBuf[Dim];
04892         unsigned* newshape = makeBuffer(dim_ - 2, newshapeBuf, Dim);
04893         unsigned ishap = 0;
04894         for (unsigned i=0; i<dim_; ++i)
04895             if (i != pos1 && i != pos2)
04896                 newshape[ishap++] = shape_[i];
04897 
04898         // Form the result array
04899         ArrayND<Numeric,Len,Dim> result(newshape, ishap);
04900         if (ishap)
04901             contractLoop(0, 0, pos1, pos2, 0UL, 0UL, result);
04902         else
04903         {
04904             // We are just calculating the trace
04905             Numeric sum = Numeric();
04906             const unsigned imax = shape_[0];
04907             const unsigned long stride = strides_[0] + strides_[1];
04908             for (unsigned i=0; i<imax; ++i)
04909                 sum += data_[i*stride];
04910             result() = sum;
04911         }
04912 
04913         destroyBuffer(newshape, newshapeBuf);
04914         return result;
04915     }
04916 
04917     template<typename Numeric, unsigned Len, unsigned Dim>
04918     void ArrayND<Numeric,Len,Dim>::transposeLoop(
04919         const unsigned level, const unsigned pos1, const unsigned pos2,
04920         unsigned long idxThis, unsigned long idxRes, ArrayND& result) const
04921     {
04922         const unsigned imax = shape_[level];
04923         const unsigned long mystride = strides_[level];
04924         const unsigned relevel = level == pos1 ? pos2 : 
04925             (level == pos2 ? pos1 : level);
04926         const unsigned long restride = result.strides_[relevel];
04927         const bool ready = (level == dim_ - 1);
04928         for (unsigned i=0; i<imax; ++i)
04929         {
04930             if (ready)
04931                 result.data_[idxRes] = data_[idxThis];
04932             else
04933                 transposeLoop(level+1, pos1, pos2, idxThis, idxRes, result);
04934             idxThis += mystride;
04935             idxRes += restride;
04936         }
04937     }
04938 
04939     template<typename Numeric, unsigned Len, unsigned Dim>
04940     template<typename Num2>
04941     Num2 ArrayND<Numeric,Len,Dim>::sum() const
04942     {
04943         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04944             "Initialize npstat::ArrayND before calling method \"sum\"");
04945         Num2 sum = Num2();
04946         for (unsigned long i=0; i<len_; ++i)
04947             sum += data_[i];
04948         return sum;
04949     }
04950 
04951     template<typename Numeric, unsigned Len, unsigned Dim>
04952     template<typename Num2>
04953     Num2 ArrayND<Numeric,Len,Dim>::sumsq() const
04954     {
04955         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04956             "Initialize npstat::ArrayND before calling method \"sumsq\"");
04957         Num2 sum = Num2();
04958         for (unsigned long i=0; i<len_; ++i)
04959         {
04960             const Num2 absval = absValue(data_[i]);
04961             sum += absval*absval;
04962         }
04963         return sum;
04964     }
04965 
04966     template<typename Numeric, unsigned Len, unsigned Dim>
04967     Numeric ArrayND<Numeric,Len,Dim>::min() const
04968     {
04969         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04970             "Initialize npstat::ArrayND before calling method \"min\"");
04971         if (dim_)
04972         {
04973             Numeric minval(data_[0]);
04974             for (unsigned long i=1UL; i<len_; ++i)
04975                 if (ComplexComparesAbs<Numeric>::less(data_[i], minval))
04976                     minval = data_[i];
04977             return minval;
04978         }
04979         else
04980             return localData_[0];
04981     }
04982 
04983     template<typename Numeric, unsigned Len, unsigned Dim>
04984     Numeric ArrayND<Numeric,Len,Dim>::min(
04985         unsigned *index, const unsigned indexLen) const
04986     {
04987         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
04988             "Initialize npstat::ArrayND before calling method \"min\"");
04989         if (indexLen != dim_) throw npstat::NpstatInvalidArgument(
04990             "In npstat::ArrayND::min: incompatible index length");
04991         if (dim_)
04992         {
04993             unsigned long minind = 0UL;
04994             Numeric minval(data_[0]);
04995             for (unsigned long i=1UL; i<len_; ++i)
04996                 if (ComplexComparesAbs<Numeric>::less(data_[i], minval))
04997                 {
04998                     minval = data_[i];
04999                     minind = i;
05000                 }
05001             convertLinearIndex(minind, index, indexLen);
05002             return minval;
05003         }
05004         else
05005             return localData_[0];
05006     }
05007 
05008     template<typename Numeric, unsigned Len, unsigned Dim>
05009     Numeric ArrayND<Numeric,Len,Dim>::max() const
05010     {
05011         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05012             "Initialize npstat::ArrayND before calling method \"max\"");
05013         if (dim_)
05014         {
05015             Numeric maxval(data_[0]);
05016             for (unsigned long i=1UL; i<len_; ++i)
05017                 if (ComplexComparesAbs<Numeric>::less(maxval, data_[i]))
05018                     maxval = data_[i];
05019             return maxval;
05020         }
05021         else
05022             return localData_[0];
05023     }
05024 
05025     template<typename Numeric, unsigned Len, unsigned Dim>
05026     Numeric ArrayND<Numeric,Len,Dim>::max(
05027         unsigned *index, const unsigned indexLen) const
05028     {
05029         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05030             "Initialize npstat::ArrayND before calling method \"max\"");
05031         if (indexLen != dim_) throw npstat::NpstatInvalidArgument(
05032             "In npstat::ArrayND::max: incompatible index length");
05033         if (dim_)
05034         {
05035             unsigned long maxind = 0UL;
05036             Numeric maxval(data_[0]);
05037             for (unsigned long i=1UL; i<len_; ++i)
05038                 if (ComplexComparesAbs<Numeric>::less(maxval, data_[i]))
05039                 {
05040                     maxval = data_[i];
05041                     maxind = i;
05042                 }
05043             convertLinearIndex(maxind, index, indexLen);
05044             return maxval;
05045         }
05046         else
05047             return localData_[0];
05048     }
05049 
05050     // Faster function for 2d transpose
05051     template<typename Numeric, unsigned Len, unsigned Dim>
05052     ArrayND<Numeric,Len,Dim> ArrayND<Numeric,Len,Dim>::transpose() const
05053     {
05054         if (dim_ != 2) throw npstat::NpstatInvalidArgument(
05055             "npstat::ArrayND::transpose method "
05056             "can not be used with arrays of rank other than 2");
05057         unsigned newshape[2];
05058         newshape[0] = shape_[1];
05059         newshape[1] = shape_[0];
05060         ArrayND<Numeric,Len,Dim> result(newshape, dim_);
05061         const unsigned imax = shape_[0];
05062         const unsigned jmax = shape_[1];
05063         for (unsigned i=0; i<imax; ++i)
05064             for (unsigned j=0; j<jmax; ++j)
05065                 result.data_[j*imax + i] = data_[i*jmax + j];
05066         return result;
05067     }
05068 
05069     template<typename Numeric, unsigned Len, unsigned Dim>
05070     template <typename Accumulator>
05071     ArrayND<Numeric,Len,Dim> ArrayND<Numeric,Len,Dim>::derivative(
05072         const double inscale) const
05073     {
05074         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05075             "Initialize npstat::ArrayND before calling method \"derivative\"");
05076         if (!dim_) throw npstat::NpstatInvalidArgument(
05077             "npstat::ArrayND::derivative method "
05078             "can not be used with array of 0 rank");
05079 
05080         const typename ProperDblFromCmpl<Accumulator>::type scale = inscale;
05081         const unsigned maxdim = CHAR_BIT*sizeof(unsigned long);
05082         if (dim_ >= maxdim) throw npstat::NpstatInvalidArgument(
05083             "In npstat::ArrayND::derivative: array rank is too large");
05084         const unsigned long maxcycle = 1UL << dim_;
05085 
05086         ArrayShape sh;
05087         sh.reserve(dim_);
05088         for (unsigned i=0; i<dim_; ++i)
05089         {
05090             if (shape_[i] <= 1U)
05091                 throw npstat::NpstatInvalidArgument(
05092                     "In npstat::ArrayND::derivative: in some dimendions "
05093                     "array size is too small");
05094             sh.push_back(shape_[i] - 1U);
05095         }
05096 
05097         ArrayND result(sh);
05098         const unsigned long rLen = result.length();
05099         for (unsigned long ilin=0; ilin<rLen; ++ilin)
05100         {
05101             result.convertLinearIndex(ilin, &sh[0], dim_);
05102 
05103             Accumulator deriv = Accumulator();
05104             for (unsigned long icycle=0UL; icycle<maxcycle; ++icycle)
05105             {
05106                 unsigned long icell = 0UL;
05107                 unsigned n1 = 0U;
05108                 for (unsigned i=0; i<dim_; ++i)
05109                 {
05110                     if (icycle & (1UL << i))
05111                     {
05112                         ++n1;
05113                         icell += strides_[i]*(sh[i] + 1);
05114                     }
05115                     else
05116                         icell += strides_[i]*sh[i];
05117                 }
05118                 if ((dim_ - n1) % 2U)
05119                     deriv -= data_[icell];
05120                 else
05121                     deriv += data_[icell];
05122             }
05123             result.data_[ilin] = static_cast<Numeric>(deriv*scale);
05124         }
05125 
05126         return result;
05127     }
05128 
05129     template<typename Numeric, unsigned Len, unsigned Dim>
05130     template <typename Accumulator>
05131     Accumulator ArrayND<Numeric,Len,Dim>::sumBelowLoop(
05132         const unsigned level, unsigned long idx0,
05133         const unsigned* limit) const
05134     {
05135         Accumulator cdf = Accumulator();
05136         const unsigned imax = limit[level] + 1U;
05137         if (level == dim_ - 1)
05138         {
05139             Numeric* base = data_ + idx0;
05140             for (unsigned i=0; i<imax; ++i)
05141                 cdf += base[i];
05142         }
05143         else
05144         {
05145             const unsigned long stride = strides_[level];
05146             for (unsigned i=0; i<imax; ++i, idx0+=stride)
05147                 cdf += sumBelowLoop<Accumulator>(level+1, idx0, limit);
05148         }
05149         return cdf;
05150     }
05151 
05152     template<typename Numeric, unsigned Len, unsigned Dim>
05153     template <typename Accumulator>
05154     Accumulator ArrayND<Numeric,Len,Dim>::cdfValue(
05155         const unsigned *index, const unsigned indexLen) const
05156     {
05157         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05158             "Initialize npstat::ArrayND before calling method \"cdfValue\"");
05159         if (!dim_) throw npstat::NpstatInvalidArgument(
05160             "npstat::ArrayND::cdfValue method "
05161             "can not be used with array of 0 rank");
05162         if (indexLen != dim_) throw npstat::NpstatInvalidArgument(
05163             "In npstat::ArrayND::cdfValue: incompatible index length");
05164         for (unsigned i=0; i<indexLen; ++i)
05165             if (index[i] >= shape_[i])
05166                 throw npstat::NpstatOutOfRange(
05167                     "In npstat::ArrayND::cdfValue: index out of range");
05168         return sumBelowLoop<Accumulator>(0, 0U, index);
05169     }
05170 
05171     template<typename Numeric, unsigned Len, unsigned Dim>
05172     template <typename Accumulator>
05173     ArrayND<Numeric,Len,Dim> ArrayND<Numeric,Len,Dim>::cdfArray(
05174         const double inscale) const
05175     {
05176         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05177             "Initialize npstat::ArrayND before calling method \"cdfArray\"");
05178         if (!dim_) throw npstat::NpstatInvalidArgument(
05179             "npstat::ArrayND::cdfArray method "
05180             "can not be used with array of 0 rank");
05181 
05182         const proper_double scale = inscale;
05183         const unsigned maxdim = CHAR_BIT*sizeof(unsigned long);
05184         if (dim_ >= maxdim)
05185             throw npstat::NpstatInvalidArgument(
05186                 "In npstat::ArrayND::cdfArray: array rank is too large");
05187         const unsigned long maxcycle = 1UL << dim_;
05188 
05189         ArrayShape sh;
05190         sh.reserve(dim_);
05191         for (unsigned i=0; i<dim_; ++i)
05192             sh.push_back(shape_[i] + 1U);
05193 
05194         ArrayND<Accumulator> result(sh);
05195 
05196         unsigned* psh = &sh[0];
05197         const unsigned long len = result.length();
05198         for (unsigned long ipre=0; ipre<len; ++ipre)
05199         {
05200             result.convertLinearIndex(ipre, psh, dim_);
05201             Accumulator deriv = Accumulator();
05202             bool has0 = false;
05203             for (unsigned i=0; i<dim_; ++i)
05204                 if (psh[i]-- == 0U)
05205                 {
05206                     has0 = true;
05207                     break;
05208                 }
05209             if (!has0)
05210             {
05211                 for (unsigned long icycle=0UL; icycle<maxcycle; ++icycle)
05212                 {
05213                     unsigned long icell = 0UL;
05214                     unsigned n1 = 0U;
05215                     for (unsigned i=0; i<dim_; ++i)
05216                     {
05217                         if (icycle & (1UL << i))
05218                         {
05219                             ++n1;
05220                             icell += result.strides_[i]*(psh[i] + 1);
05221                         }
05222                         else
05223                             icell += result.strides_[i]*psh[i];
05224                     }
05225                     if (n1 < dim_)
05226                     {
05227                         if ((dim_ - n1) % 2U)
05228                             deriv += result.data_[icell];
05229                         else
05230                             deriv -= result.data_[icell];
05231                     }
05232                 }
05233                 deriv += static_cast<Accumulator>(value(psh, dim_)*scale);
05234             }
05235             result.data_[ipre] = deriv;
05236         }
05237 
05238         // The "return" will convert Accumulator type into Numeric
05239         return result;
05240     }
05241 
05242     template<typename Numeric, unsigned Len, unsigned Dim>
05243     ArrayND<Numeric,Len,Dim> ArrayND<Numeric,Len,Dim>::transpose(
05244         const unsigned pos1, const unsigned pos2) const
05245     {
05246         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05247             "Initialize npstat::ArrayND before calling method \"transpose\"");
05248         if (!(pos1 < dim_ && pos2 < dim_ && pos1 != pos2))
05249             throw npstat::NpstatInvalidArgument("In npstat::ArrayND::transpose: "
05250                                         "incompatible transposition indices");
05251         if (dim_ == 2)
05252             return transpose();
05253         else
05254         {
05255             // Construct the new shape
05256             unsigned newshapeBuf[Dim];
05257             unsigned *newshape = makeBuffer(dim_, newshapeBuf, Dim);
05258             copyBuffer(newshape, shape_, dim_);
05259             std::swap(newshape[pos1], newshape[pos2]);
05260 
05261             // Form the result array
05262             ArrayND<Numeric,Len,Dim> result(newshape, dim_);
05263 
05264             // Fill the result array
05265             transposeLoop(0, pos1, pos2, 0UL, 0UL, result);
05266 
05267             destroyBuffer(newshape, newshapeBuf);
05268             return result;
05269         }
05270     }
05271 
05272     template<typename Numeric, unsigned Len, unsigned Dim>
05273     template<typename Num2, unsigned Len2, unsigned Dim2>
05274     void ArrayND<Numeric,Len,Dim>::multiMirror(
05275         ArrayND<Num2, Len2, Dim2>* out) const
05276     {
05277         assert(out);
05278         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05279             "Initialize npstat::ArrayND before calling method \"multiMirror\"");
05280         if (!out->shapeIsKnown_)
05281             *out = ArrayND<Num2, Len2, Dim2>(doubleShape(shape()));
05282         if (dim_ != out->dim_) throw npstat::NpstatInvalidArgument(
05283             "In npstat::ArrayND::multiMirror: incompatible argument array rank");
05284 
05285         if (dim_)
05286         {
05287             const unsigned *dshape = out->shape_;
05288             for (unsigned i=0; i<dim_; ++i)
05289                 if (dshape[i] != shape_[i]*2U) throw npstat::NpstatInvalidArgument(
05290                     "In npstat::ArrayND::multiMirror: "
05291                     "incompatible argument array shape");
05292 
05293             if (dim_ >= CHAR_BIT*sizeof(unsigned long))
05294                  throw npstat::NpstatInvalidArgument(
05295                     "In npstat::ArrayND::multiMirror: "
05296                     "array rank is too large");
05297             const unsigned long maxcycle = 1UL << dim_;
05298             std::vector<unsigned> indexbuf(dim_*2U);
05299             unsigned* idx = &indexbuf[0];
05300             unsigned* mirror = idx + dim_;
05301 
05302             for (unsigned long ipt=0; ipt<len_; ++ipt)
05303             {
05304                 unsigned long l = ipt;
05305                 for (unsigned i=0; i<dim_; ++i)
05306                 {
05307                     idx[i] = l / strides_[i];
05308                     l -= (idx[i] * strides_[i]);
05309                 }
05310                 for (unsigned long icycle=0UL; icycle<maxcycle; ++icycle)
05311                 {
05312                     for (unsigned i=0; i<dim_; ++i)
05313                     {
05314                         if (icycle & (1UL << i))
05315                             mirror[i] = dshape[i] - idx[i] - 1U;
05316                         else
05317                             mirror[i] = idx[i];
05318                     }
05319                     out->value(mirror, dim_) = data_[ipt];
05320                 }
05321             }
05322         }
05323         else
05324             out->localData_[0] = static_cast<Num2>(localData_[0]);
05325     }
05326 
05327     template<typename Numeric, unsigned Len, unsigned Dim>
05328     template<typename Num2, unsigned Len2, unsigned Dim2>
05329     void ArrayND<Numeric,Len,Dim>::rotate(
05330         const unsigned* shifts, const unsigned lenShifts,
05331         ArrayND<Num2, Len2, Dim2>* rotated) const
05332     {
05333         assert(rotated);
05334         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05335             "Initialize npstat::ArrayND before calling method \"rotate\"");
05336         // Can't rotate into itself -- it will be a mess
05337         if ((void*)rotated == (void*)this) throw npstat::NpstatInvalidArgument(
05338             "In npstat::ArrayND::rotate: can not rotate array into itself");
05339         if (!rotated->shapeIsKnown_)
05340             *rotated = *this;
05341         if (dim_ != rotated->dim_) throw npstat::NpstatInvalidArgument(
05342             "In npstat::ArrayND::rotate: incompatible argument array rank");
05343         if (lenShifts != dim_) throw npstat::NpstatInvalidArgument(
05344             "In npstat::ArrayND::rotate: incompatible dimensionality of shifts");
05345 
05346         if (dim_)
05347         {
05348             assert(shifts);
05349             if (dim_ > CHAR_BIT*sizeof(unsigned long))
05350                 throw npstat::NpstatInvalidArgument(
05351                     "In npstat::ArrayND::rotate: array rank is too large");
05352             unsigned buf[CHAR_BIT*sizeof(unsigned long)];
05353             clearBuffer(buf, dim_);
05354             (const_cast<ArrayND*>(this))->flatCircularLoop(
05355                 0U, 0UL, 0UL, buf, shape_, shifts,
05356                 *rotated, scast_assign_right<Numeric,Num2>());
05357         }
05358         else
05359             rotated->localData_[0] = static_cast<Num2>(localData_[0]);
05360     }
05361 
05362     template<typename Numeric, unsigned Len, unsigned Dim>
05363     template<typename Num2, unsigned Len2, unsigned Dim2>
05364     void ArrayND<Numeric,Len,Dim>::dotProductLoop(
05365         const unsigned level, unsigned long idx0,
05366         unsigned long idx1, unsigned long idx2,
05367         const ArrayND<Num2, Len2, Dim2>& r,
05368         ArrayND& result) const
05369     {
05370         // idx0 -- this object
05371         // idx1 -- dot product argument
05372         // idx2 -- result
05373         if (level == result.dim_)
05374         {
05375             Numeric sum = Numeric();
05376             const unsigned imax = r.shape_[0];
05377             const unsigned rstride = r.strides_[0];
05378             const Numeric* l = data_ + idx0;
05379             const Num2* ri = r.data_ + idx1;
05380             for (unsigned i=0; i<imax; ++i)
05381                 sum += l[i]*ri[i*rstride];
05382             result.data_[idx2] = sum;
05383         }
05384         else
05385         {
05386             const unsigned imax = result.shape_[level];
05387             for (unsigned i=0; i<imax; ++i)
05388             {
05389                 dotProductLoop(level+1, idx0, idx1, idx2, r, result);
05390                 idx2 += result.strides_[level];
05391                 if (level < dim_ - 1)
05392                     idx0 += strides_[level];
05393                 else
05394                     idx1 += r.strides_[level + 2 - dim_];
05395             }
05396         }
05397     }
05398 
05399     template<typename Numeric, unsigned Len, unsigned Dim>
05400     template<typename Num2, unsigned Len2, unsigned Dim2>
05401     ArrayND<Numeric,Len,Dim> ArrayND<Numeric,Len,Dim>::dot(
05402         const ArrayND<Num2,Len2,Dim2>& r) const
05403     {
05404         if (!dim_) throw npstat::NpstatInvalidArgument(
05405             "npstat::ArrayND::dot method "
05406             "can not be used with array of 0 rank");
05407         if (!r.dim_) throw npstat::NpstatInvalidArgument(
05408             "npstat::ArrayND::dot method "
05409             "can not be used with argument array of 0 rank");
05410         if (shape_[dim_ - 1] != r.shape_[0]) throw npstat::NpstatInvalidArgument(
05411             "In npstat::ArrayND::dot: incompatible argument array shape");
05412 
05413         if (dim_ == 1 && r.dim_ == 1)
05414         {
05415             // Special case: the result is of 0 rank
05416             ArrayND<Numeric,Len,Dim> result(static_cast<unsigned*>(0), 0U);
05417             Numeric sum = Numeric();
05418             const unsigned imax = shape_[0];
05419             for (unsigned i=0; i<imax; ++i)
05420                 sum += data_[i]*r.data_[i];
05421             result() = sum;
05422             return result;
05423         }
05424         else
05425         {
05426             unsigned newshapeBuf[2*Dim];
05427             unsigned *newshape = makeBuffer(dim_+r.dim_-2, newshapeBuf, 2*Dim);
05428             copyBuffer(newshape, shape_, dim_-1);
05429             copyBuffer(newshape+(dim_-1), r.shape_+1, r.dim_-1);
05430             ArrayND<Numeric,Len,Dim> result(newshape, dim_+r.dim_-2);
05431 
05432             dotProductLoop(0U, 0UL, 0UL, 0UL, r, result);
05433 
05434             destroyBuffer(newshape, newshapeBuf);
05435             return result;            
05436         }
05437     }
05438 
05439     template<typename Numeric, unsigned Len, unsigned Dim>
05440     inline unsigned ArrayND<Numeric,Len,Dim>::span(const unsigned dim) const
05441     {
05442         if (dim >= dim_)
05443             throw npstat::NpstatOutOfRange(
05444                 "In npstat::ArrayND::span: dimension number is out of range");
05445         return shape_[dim];
05446     }
05447 
05448     template<typename Numeric, unsigned Len, unsigned Dim>
05449     unsigned ArrayND<Numeric,Len,Dim>::maximumSpan() const
05450     {
05451         unsigned maxspan = 0;
05452         for (unsigned i=0; i<dim_; ++i)
05453             if (shape_[i] > maxspan)
05454                 maxspan = shape_[i];
05455         return maxspan;
05456     }
05457 
05458     template<typename Numeric, unsigned Len, unsigned Dim>
05459     unsigned ArrayND<Numeric,Len,Dim>::minimumSpan() const
05460     {
05461         if (dim_ == 0)
05462             return 0U;
05463         unsigned minspan = shape_[0];
05464         for (unsigned i=1; i<dim_; ++i)
05465             if (shape_[i] < minspan)
05466                 minspan = shape_[i];
05467         return minspan;
05468     }
05469 
05470     template<typename Numeric, unsigned Len, unsigned Dim>
05471     inline const Numeric& ArrayND<Numeric,Len,Dim>::cl() const
05472     {
05473         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05474             "Initialize npstat::ArrayND before calling method \"cl\"");
05475         if (dim_) throw npstat::NpstatInvalidArgument(
05476             "In npstat::ArrayND::cl: wrong # of args (not rank 0 array)");
05477         return localData_[0];
05478     }
05479 
05480     template<typename Numeric, unsigned Len, unsigned Dim>
05481     inline const Numeric& ArrayND<Numeric,Len,Dim>::cl(
05482         const double i0) const
05483     {
05484         if (1U != dim_) throw npstat::NpstatInvalidArgument(
05485             "In npstat::ArrayND::cl: wrong # of args (not rank 1 array)");
05486         return data_[coordToIndex(i0, 0)];
05487     }
05488 
05489     template<typename Numeric, unsigned Len, unsigned Dim>
05490     inline const Numeric& ArrayND<Numeric,Len,Dim>::cl(
05491         const double i0,
05492         const double i1) const
05493     {
05494         if (2U != dim_) throw npstat::NpstatInvalidArgument(
05495             "In npstat::ArrayND::cl: wrong # of args (not rank 2 array)");
05496         return data_[coordToIndex(i0, 0)*strides_[0] + 
05497                      coordToIndex(i1, 1)];
05498     }
05499 
05500     template<typename Numeric, unsigned Len, unsigned Dim>
05501     inline const Numeric& ArrayND<Numeric,Len,Dim>::cl(
05502         const double i0,
05503         const double i1,
05504         const double i2) const 
05505     {
05506         if (3U != dim_) throw npstat::NpstatInvalidArgument(
05507             "In npstat::ArrayND::cl: wrong # of args (not rank 3 array)");
05508         return data_[coordToIndex(i0, 0)*strides_[0] + 
05509                      coordToIndex(i1, 1)*strides_[1] + 
05510                      coordToIndex(i2, 2)];
05511     }
05512 
05513     template<typename Numeric, unsigned Len, unsigned Dim>
05514     inline const Numeric& ArrayND<Numeric,Len,Dim>::cl(
05515         const double i0,
05516         const double i1,
05517         const double i2,
05518         const double i3) const 
05519     {
05520         if (4U != dim_) throw npstat::NpstatInvalidArgument(
05521             "In npstat::ArrayND::cl: wrong # of args (not rank 4 array)");
05522         return data_[coordToIndex(i0, 0)*strides_[0] + 
05523                      coordToIndex(i1, 1)*strides_[1] + 
05524                      coordToIndex(i2, 2)*strides_[2] + 
05525                      coordToIndex(i3, 3)];
05526     }
05527 
05528     template<typename Numeric, unsigned Len, unsigned Dim>
05529     inline const Numeric& ArrayND<Numeric,Len,Dim>::cl(
05530         const double i0,
05531         const double i1,
05532         const double i2,
05533         const double i3,
05534         const double i4) const 
05535     {
05536         if (5U != dim_) throw npstat::NpstatInvalidArgument(
05537             "In npstat::ArrayND::cl: wrong # of args (not rank 5 array)");
05538         return data_[coordToIndex(i0, 0)*strides_[0] + 
05539                      coordToIndex(i1, 1)*strides_[1] + 
05540                      coordToIndex(i2, 2)*strides_[2] + 
05541                      coordToIndex(i3, 3)*strides_[3] + 
05542                      coordToIndex(i4, 4)];
05543     }
05544 
05545     template<typename Numeric, unsigned Len, unsigned Dim>
05546     inline const Numeric& ArrayND<Numeric,Len,Dim>::cl(
05547         const double i0,
05548         const double i1,
05549         const double i2,
05550         const double i3,
05551         const double i4,
05552         const double i5) const 
05553     {
05554         if (6U != dim_) throw npstat::NpstatInvalidArgument(
05555             "In npstat::ArrayND::cl: wrong # of args (not rank 6 array)");
05556         return data_[coordToIndex(i0, 0)*strides_[0] + 
05557                      coordToIndex(i1, 1)*strides_[1] + 
05558                      coordToIndex(i2, 2)*strides_[2] + 
05559                      coordToIndex(i3, 3)*strides_[3] + 
05560                      coordToIndex(i4, 4)*strides_[4] + 
05561                      coordToIndex(i5, 5)];
05562     }
05563 
05564     template<typename Numeric, unsigned Len, unsigned Dim>
05565     inline const Numeric& ArrayND<Numeric,Len,Dim>::cl(
05566         const double i0,
05567         const double i1,
05568         const double i2,
05569         const double i3,
05570         const double i4,
05571         const double i5,
05572         const double i6) const 
05573     {
05574         if (7U != dim_) throw npstat::NpstatInvalidArgument(
05575             "In npstat::ArrayND::cl: wrong # of args (not rank 7 array)");
05576         return data_[coordToIndex(i0, 0)*strides_[0] + 
05577                      coordToIndex(i1, 1)*strides_[1] + 
05578                      coordToIndex(i2, 2)*strides_[2] + 
05579                      coordToIndex(i3, 3)*strides_[3] + 
05580                      coordToIndex(i4, 4)*strides_[4] + 
05581                      coordToIndex(i5, 5)*strides_[5] +
05582                      coordToIndex(i6, 6)];
05583     }
05584 
05585     template<typename Numeric, unsigned Len, unsigned Dim>
05586     inline const Numeric& ArrayND<Numeric,Len,Dim>::cl(
05587         const double i0,
05588         const double i1,
05589         const double i2,
05590         const double i3,
05591         const double i4,
05592         const double i5,
05593         const double i6,
05594         const double i7) const 
05595     {
05596         if (8U != dim_) throw npstat::NpstatInvalidArgument(
05597             "In npstat::ArrayND::cl: wrong # of args (not rank 8 array)");
05598         return data_[coordToIndex(i0, 0)*strides_[0] + 
05599                      coordToIndex(i1, 1)*strides_[1] + 
05600                      coordToIndex(i2, 2)*strides_[2] + 
05601                      coordToIndex(i3, 3)*strides_[3] + 
05602                      coordToIndex(i4, 4)*strides_[4] + 
05603                      coordToIndex(i5, 5)*strides_[5] +
05604                      coordToIndex(i6, 6)*strides_[6] + 
05605                      coordToIndex(i7, 7)];
05606     }
05607 
05608     template<typename Numeric, unsigned Len, unsigned Dim>
05609     inline const Numeric& ArrayND<Numeric,Len,Dim>::cl(
05610         const double i0,
05611         const double i1,
05612         const double i2,
05613         const double i3,
05614         const double i4,
05615         const double i5,
05616         const double i6,
05617         const double i7,
05618         const double i8) const 
05619     {
05620         if (9U != dim_) throw npstat::NpstatInvalidArgument(
05621             "In npstat::ArrayND::cl: wrong # of args (not rank 9 array)");
05622         return data_[coordToIndex(i0, 0)*strides_[0] + 
05623                      coordToIndex(i1, 1)*strides_[1] + 
05624                      coordToIndex(i2, 2)*strides_[2] + 
05625                      coordToIndex(i3, 3)*strides_[3] + 
05626                      coordToIndex(i4, 4)*strides_[4] + 
05627                      coordToIndex(i5, 5)*strides_[5] +
05628                      coordToIndex(i6, 6)*strides_[6] + 
05629                      coordToIndex(i7, 7)*strides_[7] + 
05630                      coordToIndex(i8, 8)];
05631     }
05632 
05633     template<typename Numeric, unsigned Len, unsigned Dim>
05634     inline const Numeric& ArrayND<Numeric,Len,Dim>::cl(
05635         const double i0,
05636         const double i1,
05637         const double i2,
05638         const double i3,
05639         const double i4,
05640         const double i5,
05641         const double i6,
05642         const double i7,
05643         const double i8,
05644         const double i9) const 
05645     {
05646         if (10U != dim_) throw npstat::NpstatInvalidArgument(
05647             "In npstat::ArrayND::cl: wrong # of args (not rank 10 array)");
05648         return data_[coordToIndex(i0, 0)*strides_[0] + 
05649                      coordToIndex(i1, 1)*strides_[1] + 
05650                      coordToIndex(i2, 2)*strides_[2] + 
05651                      coordToIndex(i3, 3)*strides_[3] + 
05652                      coordToIndex(i4, 4)*strides_[4] + 
05653                      coordToIndex(i5, 5)*strides_[5] +
05654                      coordToIndex(i6, 6)*strides_[6] + 
05655                      coordToIndex(i7, 7)*strides_[7] + 
05656                      coordToIndex(i8, 8)*strides_[8] +
05657                      coordToIndex(i9, 9)];
05658     }
05659 
05660     template<typename Numeric, unsigned Len, unsigned Dim>
05661     inline Numeric& ArrayND<Numeric,Len,Dim>::cl()
05662     {
05663         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05664             "Initialize npstat::ArrayND before calling method \"cl\"");
05665         if (dim_) throw npstat::NpstatInvalidArgument(
05666             "In npstat::ArrayND::cl: wrong # of args (not rank 0 array)");
05667         return localData_[0];
05668     }
05669 
05670     template<typename Numeric, unsigned Len, unsigned Dim>
05671     inline Numeric& ArrayND<Numeric,Len,Dim>::cl(
05672         const double i0)
05673     {
05674         if (1U != dim_) throw npstat::NpstatInvalidArgument(
05675             "In npstat::ArrayND::cl: wrong # of args (not rank 1 array)");
05676         return data_[coordToIndex(i0, 0)];
05677     }
05678 
05679     template<typename Numeric, unsigned Len, unsigned Dim>
05680     inline Numeric& ArrayND<Numeric,Len,Dim>::cl(
05681         const double i0,
05682         const double i1)
05683     {
05684         if (2U != dim_) throw npstat::NpstatInvalidArgument(
05685             "In npstat::ArrayND::cl: wrong # of args (not rank 2 array)");
05686         return data_[coordToIndex(i0, 0)*strides_[0] + 
05687                      coordToIndex(i1, 1)];
05688     }
05689 
05690     template<typename Numeric, unsigned Len, unsigned Dim>
05691     inline Numeric& ArrayND<Numeric,Len,Dim>::cl(
05692         const double i0,
05693         const double i1,
05694         const double i2) 
05695     {
05696         if (3U != dim_) throw npstat::NpstatInvalidArgument(
05697             "In npstat::ArrayND::cl: wrong # of args (not rank 3 array)");
05698         return data_[coordToIndex(i0, 0)*strides_[0] + 
05699                      coordToIndex(i1, 1)*strides_[1] + 
05700                      coordToIndex(i2, 2)];
05701     }
05702 
05703     template<typename Numeric, unsigned Len, unsigned Dim>
05704     inline Numeric& ArrayND<Numeric,Len,Dim>::cl(
05705         const double i0,
05706         const double i1,
05707         const double i2,
05708         const double i3) 
05709     {
05710         if (4U != dim_) throw npstat::NpstatInvalidArgument(
05711             "In npstat::ArrayND::cl: wrong # of args (not rank 4 array)");
05712         return data_[coordToIndex(i0, 0)*strides_[0] + 
05713                      coordToIndex(i1, 1)*strides_[1] + 
05714                      coordToIndex(i2, 2)*strides_[2] + 
05715                      coordToIndex(i3, 3)];
05716     }
05717 
05718     template<typename Numeric, unsigned Len, unsigned Dim>
05719     inline Numeric& ArrayND<Numeric,Len,Dim>::cl(
05720         const double i0,
05721         const double i1,
05722         const double i2,
05723         const double i3,
05724         const double i4) 
05725     {
05726         if (5U != dim_) throw npstat::NpstatInvalidArgument(
05727             "In npstat::ArrayND::cl: wrong # of args (not rank 5 array)");
05728         return data_[coordToIndex(i0, 0)*strides_[0] + 
05729                      coordToIndex(i1, 1)*strides_[1] + 
05730                      coordToIndex(i2, 2)*strides_[2] + 
05731                      coordToIndex(i3, 3)*strides_[3] + 
05732                      coordToIndex(i4, 4)];
05733     }
05734 
05735     template<typename Numeric, unsigned Len, unsigned Dim>
05736     inline Numeric& ArrayND<Numeric,Len,Dim>::cl(
05737         const double i0,
05738         const double i1,
05739         const double i2,
05740         const double i3,
05741         const double i4,
05742         const double i5) 
05743     {
05744         if (6U != dim_) throw npstat::NpstatInvalidArgument(
05745             "In npstat::ArrayND::cl: wrong # of args (not rank 6 array)");
05746         return data_[coordToIndex(i0, 0)*strides_[0] + 
05747                      coordToIndex(i1, 1)*strides_[1] + 
05748                      coordToIndex(i2, 2)*strides_[2] + 
05749                      coordToIndex(i3, 3)*strides_[3] + 
05750                      coordToIndex(i4, 4)*strides_[4] + 
05751                      coordToIndex(i5, 5)];
05752     }
05753 
05754     template<typename Numeric, unsigned Len, unsigned Dim>
05755     inline Numeric& ArrayND<Numeric,Len,Dim>::cl(
05756         const double i0,
05757         const double i1,
05758         const double i2,
05759         const double i3,
05760         const double i4,
05761         const double i5,
05762         const double i6) 
05763     {
05764         if (7U != dim_) throw npstat::NpstatInvalidArgument(
05765             "In npstat::ArrayND::cl: wrong # of args (not rank 7 array)");
05766         return data_[coordToIndex(i0, 0)*strides_[0] + 
05767                      coordToIndex(i1, 1)*strides_[1] + 
05768                      coordToIndex(i2, 2)*strides_[2] + 
05769                      coordToIndex(i3, 3)*strides_[3] + 
05770                      coordToIndex(i4, 4)*strides_[4] + 
05771                      coordToIndex(i5, 5)*strides_[5] +
05772                      coordToIndex(i6, 6)];
05773     }
05774 
05775     template<typename Numeric, unsigned Len, unsigned Dim>
05776     inline Numeric& ArrayND<Numeric,Len,Dim>::cl(
05777         const double i0,
05778         const double i1,
05779         const double i2,
05780         const double i3,
05781         const double i4,
05782         const double i5,
05783         const double i6,
05784         const double i7) 
05785     {
05786         if (8U != dim_) throw npstat::NpstatInvalidArgument(
05787             "In npstat::ArrayND::cl: wrong # of args (not rank 8 array)");
05788         return data_[coordToIndex(i0, 0)*strides_[0] + 
05789                      coordToIndex(i1, 1)*strides_[1] + 
05790                      coordToIndex(i2, 2)*strides_[2] + 
05791                      coordToIndex(i3, 3)*strides_[3] + 
05792                      coordToIndex(i4, 4)*strides_[4] + 
05793                      coordToIndex(i5, 5)*strides_[5] +
05794                      coordToIndex(i6, 6)*strides_[6] + 
05795                      coordToIndex(i7, 7)];
05796     }
05797 
05798     template<typename Numeric, unsigned Len, unsigned Dim>
05799     inline Numeric& ArrayND<Numeric,Len,Dim>::cl(
05800         const double i0,
05801         const double i1,
05802         const double i2,
05803         const double i3,
05804         const double i4,
05805         const double i5,
05806         const double i6,
05807         const double i7,
05808         const double i8) 
05809     {
05810         if (9U != dim_) throw npstat::NpstatInvalidArgument(
05811             "In npstat::ArrayND::cl: wrong # of args (not rank 9 array)");
05812         return data_[coordToIndex(i0, 0)*strides_[0] + 
05813                      coordToIndex(i1, 1)*strides_[1] + 
05814                      coordToIndex(i2, 2)*strides_[2] + 
05815                      coordToIndex(i3, 3)*strides_[3] + 
05816                      coordToIndex(i4, 4)*strides_[4] + 
05817                      coordToIndex(i5, 5)*strides_[5] +
05818                      coordToIndex(i6, 6)*strides_[6] + 
05819                      coordToIndex(i7, 7)*strides_[7] + 
05820                      coordToIndex(i8, 8)];
05821     }
05822 
05823     template<typename Numeric, unsigned Len, unsigned Dim>
05824     inline Numeric& ArrayND<Numeric,Len,Dim>::cl(
05825         const double i0,
05826         const double i1,
05827         const double i2,
05828         const double i3,
05829         const double i4,
05830         const double i5,
05831         const double i6,
05832         const double i7,
05833         const double i8,
05834         const double i9) 
05835     {
05836         if (10U != dim_) throw npstat::NpstatInvalidArgument(
05837             "In npstat::ArrayND::cl: wrong # of args (not rank 10 array)");
05838         return data_[coordToIndex(i0, 0)*strides_[0] + 
05839                      coordToIndex(i1, 1)*strides_[1] + 
05840                      coordToIndex(i2, 2)*strides_[2] + 
05841                      coordToIndex(i3, 3)*strides_[3] + 
05842                      coordToIndex(i4, 4)*strides_[4] + 
05843                      coordToIndex(i5, 5)*strides_[5] +
05844                      coordToIndex(i6, 6)*strides_[6] + 
05845                      coordToIndex(i7, 7)*strides_[7] + 
05846                      coordToIndex(i8, 8)*strides_[8] +
05847                      coordToIndex(i9, 9)];
05848     }
05849 
05850     template<typename Numeric, unsigned StackLen, unsigned StackDim>
05851     const char* ArrayND<Numeric,StackLen,StackDim>::classname()
05852     {
05853         static const std::string name(
05854             gs::template_class_name<Numeric>("npstat::ArrayND"));
05855         return name.c_str();
05856     }
05857 
05858     template<typename Numeric, unsigned StackLen, unsigned StackDim>
05859     bool ArrayND<Numeric,StackLen,StackDim>::write(std::ostream& os) const
05860     {
05861         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05862             "Initialize npstat::ArrayND before calling method \"write\"");
05863         gs::write_pod_vector(os, shape());
05864         return !os.fail() && 
05865             (dim_ ? gs::write_array(os, data_, len_) : 
05866              gs::write_item(os, localData_[0], false));
05867     }
05868 
05869     template<typename Numeric, unsigned Len, unsigned Dim>
05870     void ArrayND<Numeric,Len,Dim>::restore(
05871         const gs::ClassId& id, std::istream& in, ArrayND* array)
05872     {
05873         static const gs::ClassId current(gs::ClassId::makeId<ArrayND<Numeric,Len,Dim> >());
05874         current.ensureSameId(id);
05875 
05876         ArrayShape rshape;
05877         gs::read_pod_vector(in, &rshape);
05878         if (in.fail()) throw gs::IOReadFailure(
05879             "In npstat::ArrayND::restore: input stream failure (checkpoint 0)");
05880 
05881         assert(array);
05882         array->uninitialize();
05883         array->dim_ = rshape.size();
05884         array->shapeIsKnown_ = true;
05885         array->len_ = 1UL;
05886         if (array->dim_)
05887         {
05888             array->shape_ = makeBuffer(array->dim_, array->localShape_, Dim);
05889             for (unsigned i=0; i<array->dim_; ++i)
05890             {
05891                 array->shape_[i] = rshape[i];
05892                 assert(array->shape_[i]);
05893                 array->len_ *= array->shape_[i];
05894             }
05895             array->buildStrides();
05896             array->data_ = makeBuffer(array->len_, array->localData_, Len);
05897             gs::read_array(in, array->data_, array->len_);
05898         }
05899         else
05900             gs::restore_item(in, array->localData_, false);
05901         if (in.fail()) throw gs::IOReadFailure(
05902             "In npstat::ArrayND::restore: input stream failure (checkpoint 1)");
05903     }
05904 
05905     template<typename Numeric, unsigned Len, unsigned StackDim>
05906     template <typename Num2, unsigned Len2, unsigned Dim2>
05907     void ArrayND<Numeric,Len,StackDim>::exportSubrange(
05908         const unsigned* corner, const unsigned lenCorner,
05909         ArrayND<Num2, Len2, Dim2>* out) const
05910     {
05911         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05912             "Initialize npstat::ArrayND before calling method \"exportSubrange\"");
05913         if (dim_ != lenCorner) throw npstat::NpstatInvalidArgument(
05914             "In npstat::ArrayND::exportSubrange: incompatible corner index length");
05915         assert(out);
05916         if (!out->shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05917             "In npstat::ArrayND::exportSubrange: uninitialized argument array");
05918         if (out->dim_ != dim_) throw npstat::NpstatInvalidArgument(
05919             "In npstat::ArrayND::exportSubrange: incompatible argument array rank");
05920 
05921         if (dim_)
05922         {
05923             assert(corner);
05924             if (dim_ > CHAR_BIT*sizeof(unsigned long))
05925                 throw npstat::NpstatInvalidArgument(
05926                     "In npstat::ArrayND::exportSubrange: "
05927                     "array rank is too large");
05928             unsigned toBuf[CHAR_BIT*sizeof(unsigned long)];
05929             clearBuffer(toBuf, dim_);
05930             (const_cast<ArrayND*>(this))->commonSubrangeLoop(
05931                 0U, 0UL, 0UL, corner, out->shape_, toBuf, *out,
05932                 scast_assign_right<Numeric,Num2>());
05933         }
05934         else
05935             out->localData_[0] = static_cast<Num2>(localData_[0]);
05936     }
05937 
05938     template<typename Numeric, unsigned Len, unsigned StackDim>
05939     template <typename Num2, unsigned Len2, unsigned Dim2>
05940     void ArrayND<Numeric,Len,StackDim>::importSubrange(
05941         const unsigned* corner, const unsigned lenCorner,
05942         const ArrayND<Num2, Len2, Dim2>& from)
05943     {
05944         if (!shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05945             "Initialize npstat::ArrayND before calling method \"importSubrange\"");
05946         if (dim_ != lenCorner) throw npstat::NpstatInvalidArgument(
05947             "In npstat::ArrayND::importSubrange: incompatible corner index length");
05948         if (!from.shapeIsKnown_) throw npstat::NpstatInvalidArgument(
05949             "In npstat::ArrayND::importSubrange: uninitialized argument array");
05950         if (from.dim_ != dim_) throw npstat::NpstatInvalidArgument(
05951             "In npstat::ArrayND::importSubrange: incompatible argument array rank");
05952 
05953         if (dim_)
05954         {
05955             assert(corner);
05956             if (dim_ > CHAR_BIT*sizeof(unsigned long))
05957                 throw npstat::NpstatInvalidArgument(
05958                     "In npstat::ArrayND::importSubrange: "
05959                     "array rank is too large");
05960             unsigned toBuf[CHAR_BIT*sizeof(unsigned long)];
05961             clearBuffer(toBuf, dim_);
05962             commonSubrangeLoop(0U, 0UL, 0UL, corner, from.shape_, toBuf,
05963                                const_cast<ArrayND<Num2, Len2, Dim2>&>(from),
05964                                scast_assign_left<Numeric,Num2>());
05965         }
05966         else
05967             localData_[0] = static_cast<Numeric>(from.localData_[0]);
05968     }
05969 }
05970 
05971 
05972 #endif // NPSTAT_ARRAYND_HH_
05973