utilities.h

Go to the documentation of this file.
00001 
00015 #ifndef _DLR_NUMERIC_UTILITIES_H_
00016 #define _DLR_NUMERIC_UTILITIES_H_
00017 
00018 #include <cmath>
00019 // #include <iostream>
00020 #include <cstdlib>
00021 
00022 #include <dlrCommon/tags.h>
00023 #include <dlrNumeric/numericTraits.h>
00024 #include <dlrNumeric/array1D.h>
00025 #include <dlrNumeric/array2D.h>
00026 #include <dlrNumeric/array3D.h>
00027 #include <dlrNumeric/index2D.h>
00028 #include <dlrNumeric/vector2D.h>
00029 #include <dlrNumeric/vector3D.h>
00030 
00031 namespace dlr {
00032 
00033   namespace numeric {
00034     
00035           namespace constants {
00036 
00037                   const double pi = 3.141592653589793238;
00038 
00039           } // nameapace contants
00040 
00053     template <class Type>
00054     Array1D<Type>
00055     abs(const Array1D<Type>& array0);
00056 
00057   
00070     template <class Type>
00071     Array2D<Type>
00072     abs(const Array2D<Type>& array0);
00073 
00074 
00084     template <class Type>
00085     bool
00086     allFalse(const Array1D<Type>& array0);
00087 
00088   
00098     template <class Type>
00099     bool
00100     allTrue(const Array1D<Type>& array0);
00101 
00102   
00112     template <class Type>
00113     inline bool
00114     anyFalse(const Array1D<Type>& array0);
00115 
00116   
00126     template <class Type>
00127     inline bool
00128     anyTrue(const Array1D<Type>& array0);
00129 
00130   
00141     template <class Type>
00142     inline size_t
00143     argmax(const Array1D<Type>& array0);
00144 
00145 
00159     template <class IterType>
00160     inline size_t
00161     argmax(IterType beginIter, IterType endIter);
00162 
00163 
00185     template <class Type, class Functor>
00186     inline size_t
00187     argmax(const Array1D<Type>& array0, Functor comparator);
00188   
00189 
00214     template <class IterType, class Functor>
00215     inline size_t
00216     argmax(IterType beginIter, IterType endIter, Functor comparator);
00217   
00218 
00228     template <class Type>
00229     inline Index2D
00230     argmax2D(const Array2D<Type>& array0);
00231 
00232 
00251     template <class Type, class Functor>
00252     inline Index2D
00253     argmax2D(const Array2D<Type>& array0, Functor comparator);
00254   
00255 
00266     template <class Type>
00267     inline size_t
00268     argmin(const Array1D<Type>& array0);
00269 
00270 
00288     template <class Type, class Functor>
00289     inline size_t
00290     argmin(const Array1D<Type>& array0, Functor comparator);
00291 
00292 
00302     template <class Type>
00303     inline Index2D
00304     argmin2D(const Array2D<Type>& array0);
00305 
00306 
00321     template <class Type, class Functor>
00322     inline Index2D
00323     argmin2D(const Array2D<Type>& array0, Functor comparator);
00324 
00325 
00337     template <class Type>
00338     Array1D<size_t>
00339     argsort(const Array1D<Type>& array0);
00340 
00341   
00342 //   /** 
00343 //    * This function returns an array of indices, result, so that the
00344 //    * sequence (array0[result[0]], array0[result[1]],
00345 //    * array0[result[2]], ...) is sorted from smallest to largest using
00346 //    * the supplied comparison operator.
00347 //    *
00348 //    * @param array0 The of this array will be compared to each other in
00349 //    * order to establish the correct sequence of indices.
00350 //    *
00351 //    * @param comparator This argument is a functor which supports the
00352 //    * std::binary_function<Type, Type, bool> interface, and returns
00353 //    * true if its first argument is smaller than its second argument.
00354 //    *
00355 //    * @return An array of indices as described above.
00356 //    */
00357 //   template <class Type, class Functor>
00358 //   Array1D<size_t>
00359 //   argsort(const Array1D<Type>& array0, Functor comparator);
00360 
00361   
00371     template <class Type>
00372     Array1D<Type>
00373     axisMax(const Array2D<Type>& array0,
00374             size_t axis) {return axisMaximum(array0, axis);}
00375 
00392     template <class Type>
00393     inline Array1D<Type>
00394     axisMaximum(const Array2D<Type>& array0, size_t axis);
00395 
00426     template <class Type, class Functor>
00427     Array1D<Type>
00428     axisMaximum(const Array2D<Type>& array0, size_t axis, Functor comparator);
00429 
00439     template <class Type>
00440     inline Array1D<Type>
00441     axisMin(const Array2D<Type>& array0,
00442             size_t axis) {return axisMinimum(array0, axis);}
00443   
00460     template <class Type>
00461     inline Array1D<Type>
00462     axisMinimum(const Array2D<Type>& array0, size_t axis);
00463 
00494     template <class Type, class Functor>
00495     Array1D<Type>
00496     axisMinimum(const Array2D<Type>& array0, size_t axis, Functor comparator);
00497 
00522     template <class Type>
00523     inline Array1D<typename NumericTraits<Type>::SumType>
00524     axisSum(const Array2D<Type>& array0, size_t axis);
00525 
00548     template <class Type, class ResultType>
00549     inline Array1D<ResultType>
00550     axisSum(const Array2D<Type>& array0, size_t axis,
00551             type_tag<ResultType> resultTag);
00552 
00592     template <class Type, class ResultType, class Functor>
00593     Array1D<ResultType>
00594     axisSum(const Array2D<Type>& array0, size_t axis,
00595             type_tag<ResultType> resultTag,
00596             const ResultType& initialValue, Functor adder);
00597 
00625     template <class Type>
00626     Array2D<Type>
00627     columnIndices(size_t rows, size_t columns, type_tag<Type> typeTag);
00628 
00660     template <class Type0, class Type1>
00661     inline Array1D<Type1>
00662     compress(const Array1D<Type0>& condition, const Array1D<Type1>& input);
00663 
00690     template <class Type0, class Type1>
00691     Array1D<Type1>
00692     compress(const Array1D<Type0>& condition, const Array1D<Type1>& input,
00693              size_t numTrue);
00694 
00695 
00706     template <class Type>
00707     inline size_t
00708     count(const Array1D<Type>& array0);
00709   
00723     inline Vector3D
00724     cross(const Vector3D& vector0, const Vector3D& vector1);
00725   
00737     template <class Type>
00738     inline typename NumericTraits<Type>::ProductType
00739     dot(const Array1D<Type>& array0, const Array1D<Type>& array1);
00740 
00755     template <class Type0, class Type1, class Type2>
00756     inline Type2
00757     dot(const Array1D<Type0>& array0, const Array1D<Type1>& array1,
00758         type_tag<Type2> typeTag);
00759 
00769     inline double
00770     dot(const Vector2D& vector0, const Vector2D& vector1);
00771 
00781     inline double
00782     dot(const Vector3D& vector0, const Vector3D& vector1);
00783 
00805     template <class Type>
00806     Array2D<Type>
00807     equivalentMatrix(const Array1D<Type>& vector0, size_t rowsInMatrix);
00808   
00809 
00832     template <class Type>
00833     void
00834     getMeanAndCovariance(const Array2D<Type>& sampleArray,
00835                          Array1D<double>& mean,
00836                          Array2D<double>& covariance,
00837                          size_t majorAxis=0);
00838   
00839                      
00857     template <class Type>
00858     Array2D<Type>
00859     identity(size_t rows, size_t columns, type_tag<Type> typeTag);
00860 
00861 
00871     template <class Type>
00872     Array1D<Type>
00873     ln(const Array1D<Type>& array0);
00874   
00875 
00885     template <class Type>
00886     Array2D<Type>
00887     ln(const Array2D<Type>& array0);
00888   
00889 
00910     template <class Type>
00911     Array2D<Type>
00912     logicalNot(const Array2D<Type>& array0);
00913 
00923     template <class Type>
00924     inline Type
00925     magnitude(const Array1D<Type>& array0);
00926 
00936     inline double
00937     magnitude(const Vector2D& vector0);
00938 
00948     inline double
00949     magnitude(const Vector3D& vector0);
00950 
00951   
00962     template <class Type>
00963     inline typename NumericTraits<Type>::ProductType
00964     magnitudeSquared(const Array1D<Type>& array0);
00965 
00966   
00977     inline double
00978     magnitudeSquared(const Vector2D& vector0);
00979 
00980   
00991     inline double
00992     magnitudeSquared(const Vector3D& vector0);
00993   
00994 
01012     template <class Type>
01013     inline Array1D<typename NumericTraits<Type>::ProductType>
01014     matrixMultiply(const Array1D<Type>& vector0, const Array2D<Type>& matrix0);
01015 
01033     template <class Type0, class Type1, class Type2>
01034     Array1D<Type2>
01035     matrixMultiply(const Array1D<Type0>& vector0, const Array2D<Type0>& matrix0,
01036                    type_tag<Type2> typeTag);
01037 
01054     template <class Type>
01055     inline Array1D<typename NumericTraits<Type>::ProductType>
01056     matrixMultiply(const Array2D<Type>& matrix0, const Array1D<Type>& vector0);
01057 
01075     template <class Type0, class Type1, class Type2>
01076     Array1D<Type2>
01077     matrixMultiply(const Array2D<Type0>& matrix0, const Array1D<Type1>& vector0,
01078                    type_tag<Type2> typeTag);
01079 
01080 
01095     template <class Type>
01096     inline Array2D<typename NumericTraits<Type>::ProductType>
01097     matrixMultiply(const Array2D<Type>& matrix0, const Array2D<Type>& matrix1);
01098     
01116     template <class Type0, class Type1, class Type2>
01117     Array2D<Type2>
01118     matrixMultiply(const Array2D<Type0>& matrix0, const Array2D<Type1>& matrix1,
01119                    type_tag<Type2> typeTag);
01120 
01121 
01122     // The next function is commented out because some environments use
01123     // #define directives for min() and max(), which don't obey
01124     // namespaces, and makes the code not compile if we define our own
01125     // min/max.
01126     // 
01127     // 
01128     // /** 
01129     // * This function is an alias for the function maximum(const
01130     // * Array1D&) below.
01131     // * 
01132     // * @param array0 See documentation for maximum(const Array1D&).
01133     // *
01134     // * @return See documentation for maximum(const Array1D&).
01135     // */
01136     // template <class Type>
01137     // inline Type
01138     // max(const Array1D<Type>& array0) {return maximum(array0);}
01139 
01149     template <class Type>
01150     inline Type
01151     maximum(const Array1D<Type>& array0);
01152 
01172     template <class Type, class Functor>
01173     Type
01174     maximum(const Array1D<Type>& array0, Functor comparator);
01175 
01176     
01188     template <class Iterator, class Type>
01189     Type
01190     mean(const Iterator& beginIter, const Iterator& endIter);
01191 
01192     
01204     template <class Type>
01205     inline double
01206     mean(const Array1D<Type>& array0);
01207 
01208     
01225     template <class Type0, class Type1>
01226     inline Type1
01227     mean(const Array1D<Type0>& array0, type_tag<Type1> typeTag);
01228   
01229 
01230     // The next function is commented out because some environments use
01231     // #define directives for min() and max(), which don't obey
01232     // namespaces, and makes the code not compile if we define our own
01233     // min/max.
01234     // 
01235     // 
01236     // /** 
01237     // * This function is an alias for the function minimum(const
01238     // * Array1D&) below.
01239     // * 
01240     // * @param array0 See documentation for minimum(const Array1D&).
01241     // *
01242     // * @return See documentation for minimum(const Array1D&).
01243     // */
01244     // template <class Type>
01245     // inline Type
01246     // min(const Array1D<Type>& array0) {return minimum(array0);}
01247 
01257     template <class Type>
01258     inline Type
01259     minimum(const Array1D<Type>& array0);
01260 
01280     template <class Type, class Functor>
01281     Type
01282     minimum(const Array1D<Type>& array0, Functor comparator);
01283 
01284 
01312     template <class FUNCTOR>
01313     double newtonRaphson(double startPoint, FUNCTOR objectiveFunction,
01314                          double epsilon, size_t maxIterations);
01315   
01337     template <class Type>
01338     inline double
01339     normalizedCorrelation(const Array1D<Type>& signal0,
01340                           const Array1D<Type>& signal1);
01341 
01342     
01360     template <class Type, class Type2>
01361     Type2
01362     normalizedCorrelation(const Array1D<Type>& signal0,
01363                           const Array1D<Type>& signal1,
01364                           type_tag<Type2> typeTag);
01365 
01378     template <class Type>
01379     inline Array1D<Type>
01380     ones(int size, type_tag<Type> typeTag);
01381 
01397     template <class Type>
01398     inline Array2D<Type>
01399     ones(int rows, int columns, type_tag<Type> typeTag);
01400 
01416     template <class Type>
01417     inline Array2D<typename NumericTraits<Type>::ProductType>
01418     outerProduct(const Array1D<Type>& array0, const Array1D<Type>& array1);
01419 
01439     template <class Type0, class Type1, class Type2>
01440     Array2D<Type2>
01441     outerProduct(const Array1D<Type0>& array0, const Array1D<Type1>& array1,
01442                  type_tag<Type2> typeTag);
01443 
01483     template <class Type>
01484     Array1D<Type>
01485     range(Type start, Type stop, Type stride=1);
01486 
01502     template <class Type>
01503     inline Array1D<Type>
01504     ravel(Array2D<Type>& inputArray) {return inputArray.ravel();}
01505 
01517     template <class Type>
01518     inline const Array1D<Type>
01519     ravel(const Array2D<Type>& inputArray) {return inputArray.ravel();}
01520 
01521 
01533     template <class Type>
01534     inline Type
01535     rms(const Array1D<Type>& array0);
01536 
01537 
01554     template <class Type0, class Type1>
01555     Type1
01556     rms(const Array1D<Type0>& array0, type_tag<Type1> typeTag);
01557 
01558 
01585     template <class Type>
01586     Array2D<Type>
01587     rowIndices(size_t rows, size_t columns, type_tag<Type> typeTag);
01588 
01589 
01604     template <class Type0, class Type1>
01605     inline bool
01606     shapeMatch(const Array1D<Type0>& array0, const Array1D<Type1>& array1);
01607 
01608 
01623     template <class Type0, class Type1>
01624     inline bool
01625     shapeMatch(const Array2D<Type0>& array0, const Array2D<Type1>& array1);
01626 
01627 
01642     template <class Type0, class Type1>
01643     inline bool
01644     shapeMatch(const Array3D<Type0>& array0, const Array3D<Type1>& array1);
01645 
01646 
01655     template <class Type>
01656     inline Array2D<Type>
01657     skewSymmetric(const Array1D<Type>& vector0);
01658 
01659 
01718     template <class Type>
01719     void
01720     solveQuadratic(Type c0, Type c1, Type c2,
01721                    Type& root0, Type& root1, bool& valid,
01722                    bool checkValidity=true);
01723 
01724   
01742     template <class Type>
01743     inline double
01744     standardDeviation(const Array1D<Type>& array0);
01745 
01769     template <class Type0, class Type1>
01770     inline Type1
01771     standardDeviation(const Array1D<Type0>& array0, type_tag<Type1> typeTag);
01772   
01773 
01783     template <class Type>
01784     inline typename NumericTraits<Type>::SumType
01785     sum(const Array1D<Type>& array0);
01786 
01787     
01801     template <class Type, class Type2>
01802     Type2
01803     sum(const Array1D<Type>& array0, type_tag<Type2> typeTag);
01804 
01805 
01826     template <class Type>
01827     inline typename NumericTraits<Type>::SumType
01828     sum(const Array2D<Type>& array0,
01829         const Index2D& upperLeftCorner,
01830         const Index2D& lowerRightCorner);
01831 
01832     
01857     template <class Type, class Type2>
01858     Type2
01859     sum(const Array2D<Type>& array0,
01860         const Index2D& upperLeftCorner,
01861         const Index2D& lowerRightCorner,
01862         type_tag<Type2> typeTag);
01863 
01864 
01882     template <class Type>
01883     inline double
01884     variance(const Array1D<Type>& array0);
01885 
01908     template <class Type0, class Type1>
01909     inline Type1
01910     variance(const Array1D<Type0>& array0, type_tag<Type1> typeTag);
01911 
01924     template <class Type>
01925     inline Array1D<Type>
01926     zeros(size_t size, type_tag<Type> typeTag);
01927 
01943     template <class Type>
01944     inline Array2D<Type>
01945     zeros(size_t rows, size_t columns, type_tag<Type> typeTag);
01946 
01965     template <class Type>
01966     inline Array3D<Type>
01967     zeros(size_t shape0, size_t shape1, size_t shape2, type_tag<Type> typeTag);
01968 
01969   } // namespace numeric
01970 
01971 } // namespace dlr
01972 
01973 
01974 /* ======= Declarations to maintain compatibility with legacy code. ======= */
01975 
01976 namespace dlr {
01977 
01978   using numeric::abs;
01979   using numeric::abs;
01980   using numeric::allFalse;
01981   using numeric::allTrue;
01982   using numeric::anyFalse;
01983   using numeric::anyTrue;
01984   using numeric::argmax;
01985   using numeric::argmin;
01986   using numeric::argsort;
01987   using numeric::axisMax;
01988   using numeric::axisMaximum;
01989   using numeric::axisMin;
01990   using numeric::axisMinimum;
01991   using numeric::axisSum;
01992   using numeric::columnIndices;
01993   using numeric::compress;
01994   using numeric::count;
01995   using numeric::cross;
01996   using numeric::dot;
01997   using numeric::equivalentMatrix;
01998   using numeric::getMeanAndCovariance;
01999   using numeric::identity;
02000   using numeric::ln;
02001   using numeric::logicalNot;
02002   using numeric::magnitude;
02003   using numeric::magnitudeSquared;
02004   using numeric::matrixMultiply;
02005   using numeric::maximum;
02006   using numeric::mean;
02007   using numeric::minimum;
02008   using numeric::newtonRaphson;
02009   using numeric::normalizedCorrelation;
02010   using numeric::ones;
02011   using numeric::outerProduct;
02012   using numeric::range;
02013   using numeric::ravel;
02014   using numeric::rms;
02015   using numeric::rowIndices;
02016   using numeric::shapeMatch;
02017   using numeric::skewSymmetric;
02018   using numeric::solveQuadratic;
02019   using numeric::standardDeviation;
02020   using numeric::sum;
02021   using numeric::variance;
02022   using numeric::zeros;
02023 
02024 } // namespace dlr
02025 
02026 
02027 /* ================ Definitions follow ================ */
02028 
02029 #include <cmath>
02030 #include <sstream>
02031 #include <numeric>
02032 //#include <algorithm>
02033 
02034 namespace dlr {
02035 
02036   namespace numeric {
02037     
02049     namespace privateCode {
02050 
02056       template <class Type>
02057       struct absFunctor : public std::unary_function<Type, Type> {
02065         inline Type operator()(const Type& input) {
02066           DLR_THROW3(NotImplementedException,
02067                      "absFunctor<Type>::operator()(const Type&)",
02068                      "absFunctor must be specialized for each type.");
02069           return static_cast<Type>(0);
02070         }
02071       };
02072 
02076       template <>
02077       struct absFunctor<long double>
02078         : public std::unary_function<long double, long double> {
02085         inline double operator()(const long double& input) {
02086           // fabsl doesn't appear to be commonly available.
02087           // return std::fabsl(input);
02088           return (input > 0.0) ? input : -input;
02089         }
02090       };
02091 
02092 
02096       template <>
02097       struct absFunctor<double> : public std::unary_function<double, double> {
02104         inline double operator()(const double& input) {
02105           return std::fabs(input);
02106         }
02107       };
02108 
02109 
02113       template <>
02114       struct absFunctor<float> : public std::unary_function<float, float> {
02121         inline float operator()(const float& input) {
02122           // Strange.  fabsf shows up in the global namespace.  Is this
02123           // a bug in the g++ 3.3 stand library?
02124           return fabsf(input);
02125         }
02126       };
02127 
02128 
02132       template <>
02133       struct absFunctor<long int>
02134         : public std::unary_function<long int, long int> {
02141         inline long int operator()(const long int& input) {
02142           return std::labs(input);
02143         }
02144       };
02145 
02146 
02150       template <>
02151       struct absFunctor<long long int>
02152         : public std::unary_function<long long int, long long int> {
02159         inline long long int operator()(const long long int& input) {
02160           // Many compilers don't support C99.
02161           // return std::llabs(input);
02162           return input >= 0LL ? input : -input;
02163         }
02164       };
02165 
02166 
02170       template <>
02171       struct absFunctor<int> : public std::unary_function<int, int> {
02178         inline int operator()(const int& input) {
02179           return std::abs(input);
02180         }
02181       };
02182 
02183 
02184     }
02188     // This function returns an array of the same size and element type
02189     // as its input argument, in which each element is set to the
02190     // absolute value of the corresponding element of the input array.
02191     template <class Type>
02192     Array1D<Type>
02193     abs(const Array1D<Type>& array0)
02194     {
02195       Array1D<Type> result(array0.size());
02196       std::transform(array0.begin(), array0.end(), result.begin(),
02197                      privateCode::absFunctor<Type>());
02198       return result;
02199     }
02200 
02201     // This function returns an array of the same size and element type
02202     // as its input argument, in which each element is set to the
02203     // absolute value of the corresponding element of the input array.
02204     template <class Type>
02205     Array2D<Type>
02206     abs(const Array2D<Type>& array0)
02207     {
02208       Array2D<Type> result(array0.rows(), array0.columns());
02209       std::transform(array0.begin(), array0.end(), result.begin(),
02210                      privateCode::absFunctor<Type>());
02211       return result;
02212     }
02213 
02214 
02215     // This function returns true if each element of its argument is
02216     // false, and returns false otherwise.
02217     template <class Type>
02218     bool
02219     allFalse(const Array1D<Type>& array0)
02220     {
02221       for(typename Array1D<Type>::const_iterator iter = array0.begin();
02222           iter != array0.end();
02223           ++iter) {
02224         if(*iter) {
02225           return false;
02226         }
02227       }
02228       return true;
02229     }
02230 
02231   
02232     // This function returns true if each element of its argument is
02233     // true, and returns false otherwise.
02234     template <class Type>
02235     bool
02236     allTrue(const Array1D<Type>& array0)
02237     {
02238       for(typename Array1D<Type>::const_iterator iter = array0.begin();
02239           iter != array0.end();
02240           ++iter) {
02241         if(!(*iter)) {
02242           return false;
02243         }
02244       }
02245       return true;
02246     }
02247 
02248   
02249     // This function returns true if any element of its argument is
02250     // false, and returns false otherwise.
02251     template <class Type>
02252     inline bool
02253     anyFalse(const Array1D<Type>& array0)
02254     {
02255       return !allTrue(array0);
02256     }
02257 
02258   
02259     // This function returns true if any element of its argument is
02260     // true, and returns false otherwise.
02261     template <class Type>
02262     inline bool
02263     anyTrue(const Array1D<Type>& array0)
02264     {
02265       return !allFalse(array0);
02266     }
02267 
02268   
02269     // This function returns the index of the largest element of its input
02270     // array.
02271     template <class Type>
02272     inline size_t
02273     argmax(const Array1D<Type>& array0)
02274     {
02275       return argmax(array0, std::less<Type>());
02276     }
02277 
02278 
02279     // This function returns the index of the largest element of its input
02280     // sequence.
02281     template <class IterType>
02282     inline size_t
02283     argmax(IterType beginIter, IterType endIter)
02284     {
02285       return argmax(beginIter, endIter, std::less<IterType>());
02286     }
02287 
02288 
02289     // This function returns the index of the largest element of its
02290     // input array, where largeness is defined by the second argument.
02291     template <class Type, class Functor>
02292     inline size_t
02293     argmax(const Array1D<Type>& array0, Functor comparator)
02294     {
02295       return argmax(array0.begin(), array0.end(), comparator);
02296     }
02297   
02298 
02299     // This function returns the index of the largest element of its
02300     // input sequence, where largeness is defined by the second argument.
02301     template <class IterType, class Functor>
02302     inline size_t
02303     argmax(IterType beginIter, IterType endIter, Functor comparator)
02304     {
02305       return static_cast<size_t>(
02306         std::max_element(beginIter, endIter, comparator) - beginIter);
02307     }
02308 
02309 
02310     // This function returns an Index2D instance indicating which is
02311     // the largest element of its input array.
02312     template <class Type>
02313     inline Index2D
02314     argmax2D(const Array2D<Type>& array0)
02315     {
02316       return argmax2D(array0, std::less<Type>());
02317     }
02318 
02319 
02320     // This function returns an Index2D instance indicating which is
02321     // the largest element of its input array, where largeness is
02322     // defined by the second argument.
02323     template <class Type, class Functor>
02324     inline Index2D
02325     argmax2D(const Array2D<Type>& array0, Functor comparator)
02326     {
02327       size_t ravelIndex = argmax(array0.ravel(), comparator);
02328       size_t row = ravelIndex / array0.columns(); // Int division.
02329       size_t column = ravelIndex - row * array0.columns();
02330       return Index2D(row, column);
02331     }
02332   
02333 
02334     // This function returns the index of the smallest element of its input
02335     // array.
02336     template <class Type>
02337     inline size_t
02338     argmin(const Array1D<Type>& array0)
02339     {
02340       return argmin(array0, std::less<Type>());
02341     }
02342 
02343 
02344     // This function returns the index of the smallest element of its
02345     // input array, where largeness is defined by the second argument.
02346     template <class Type, class Functor>
02347     inline size_t
02348     argmin(const Array1D<Type>& array0, Functor comparator)
02349     {
02350       const Type* minPtr = std::min_element(array0.begin(), array0.end(),
02351                                             comparator);
02352       return static_cast<size_t>(minPtr - array0.begin());
02353     }
02354 
02355 
02356     // This function returns an Index2D instance indicating which is
02357     // the smallest element of its input array.
02358     template <class Type>
02359     inline Index2D
02360     argmin2D(const Array2D<Type>& array0)
02361     {
02362       return argmin2D(array0, std::less<Type>());
02363     }
02364 
02365 
02366     // This function returns an Index2D instance indicating which is
02367     // the smallest element of its input array, where smallness is
02368     // defined by the second argument.
02369     template <class Type, class Functor>
02370     inline Index2D
02371     argmin2D(const Array2D<Type>& array0, Functor comparator)
02372     {
02373       size_t ravelIndex = argmin(array0.ravel(), comparator);
02374       size_t row = ravelIndex / array0.columns(); // Int division.
02375       size_t column = ravelIndex - row * array0.columns();
02376       return Index2D(row, column);
02377     }
02378 
02379 
02380     // This function returns an array of indices, result, so that the
02381     // sequence (array0[result[0]], array0[result[1]],
02382     // array0[result[2]], ...) is sorted from smallest to largest using
02383     // operator<().
02384     template <class Type>
02385     Array1D<size_t>
02386     argsort(const Array1D<Type>& array0)
02387     {
02388       Array1D< std::pair<Type, size_t> > sortVector(array0.size());
02389       Array1D<size_t> resultVector(array0.size());
02390 
02391       for(size_t index0 = 0; index0 < array0.size(); ++index0) {
02392         sortVector[index0] = std::pair<Type, size_t>(array0[index0], index0);
02393       }
02394       std::sort(sortVector.begin(), sortVector.end());
02395       std::transform(sortVector.begin(), sortVector.end(), resultVector.begin(),
02396                      ExtractSecondFunctor<Type, size_t>());
02397       return resultVector;    
02398     }
02399 
02400   
02401 //   // This function returns an array of indices, result, so that the
02402 //   // sequence (array0[result[0]], array0[result[1]],
02403 //   // array0[result[2]], ...) is sorted from smallest to largest using
02404 //   // the supplied comparison operator.
02405 //   template <class Type, class Functor>
02406 //   Array1D<size_t>
02407 //   argsort(const Array1D<Type>& array0, Functor comparator)
02408 //   {
02409 //     Array1D< std::pair<Type, size_t> > sortVector(array0.size());
02410 //     Array1D<size_t> resultVector(array0.size());
02411 
02412 //     for(size_t index0 = 0; index0 < array0.size(); ++index0) {
02413 //       sortVector[index0] = std::pair<Type, size_t>(array0[index0], index0);
02414 //     }
02415 //     std::sort(sortVector.begin(), sortVector.end(), comparator);
02416 //     std::transform(sortVector.begin(), sortVector.end(), resultVector.begin(),
02417 //                    ExtractSecondFunctor<Type, size_t>());
02418 //     return resultVector;    
02419 //   }
02420 
02421   
02422     // This function returns an Array1D in which each element has the
02423     // value of the largest element in one row or column of the input
02424     // Array2D.
02425     template <class Type>
02426     inline Array1D<Type>
02427     axisMaximum(const Array2D<Type>& array0, size_t axis)
02428     {
02429       return axisMaximum(array0, axis, std::less<Type>());
02430     }
02431 
02432 
02433     // This function returns an Array1D in which each element has the
02434     // value of the largest element in one row or column of the input
02435     // Array2D, where largeness is defined by the third argument.
02436     template <class Type, class Functor>
02437     Array1D<Type>
02438     axisMaximum(const Array2D<Type>& array0, size_t axis, Functor comparator)
02439     {
02440       Array1D<Type> result;
02441       switch(axis) {
02442       case 0:
02443         result.reinit(array0.columns());
02444         for(size_t column = 0; column < array0.columns(); ++column) {
02445           const Type* dataPtr = array0.data(0, column);
02446           Type columnMax = *dataPtr;
02447           size_t stride = array0.columns();
02448           for(size_t row = 0; row < array0.rows(); ++row) {
02449             if(!comparator(*dataPtr, columnMax)) {
02450               columnMax = *dataPtr;
02451             }
02452             dataPtr += stride;
02453           }
02454           result(column) = columnMax;
02455         }
02456         break;
02457       case 1:
02458         result.reinit(array0.rows());
02459         for(size_t row = 0; row < array0.rows(); ++row) {
02460           const Type* dataPtr = array0.data(row, 0);
02461           Type rowMax = *dataPtr;
02462           for(size_t column = 0; column < array0.columns(); ++column) {
02463             if(!comparator(*dataPtr, rowMax)) {
02464               rowMax = *dataPtr;
02465             }
02466             ++dataPtr;
02467           }
02468           result(row) = rowMax;
02469         }
02470         break;
02471       default:
02472         std::ostringstream message;
02473         message << "Axis " << axis << " is invalid for an Array2D.";
02474         DLR_THROW3(IndexException, "axisMaximum(const Array2D&, size_t, ...)",
02475                    message.str().c_str());
02476         break;
02477       }
02478       return result;  
02479     }
02480 
02481 
02482     // This function returns an Array1D in which each element has the
02483     // value of the smallest element in one row or column of the input
02484     // Array2D.
02485     template <class Type>
02486     inline Array1D<Type>
02487     axisMinimum(const Array2D<Type>& array0, size_t axis)
02488     {
02489       return axisMinimum(array0, axis, std::less<Type>());
02490     }
02491 
02492 
02493     // This function returns an Array1D in which each element has the
02494     // value of the smallest element in one row or column of the input
02495     // Array2D, where smallness is defined by the third argument.
02496     template <class Type, class Functor>
02497     Array1D<Type>
02498     axisMinimum(const Array2D<Type>& array0, size_t axis, Functor comparator)
02499     {
02500       Array1D<Type> result;
02501       switch(axis) {
02502       case 0:
02503         result.reinit(array0.columns());
02504         for(size_t column = 0; column < array0.columns(); ++column) {
02505           const Type* dataPtr = array0.data(0, column);
02506           Type columnMax = *dataPtr;
02507           size_t stride = array0.columns();
02508           for(size_t row = 0; row < array0.rows(); ++row) {
02509             if(comparator(*dataPtr, columnMax)) {
02510               columnMax = *dataPtr;
02511             }
02512             dataPtr += stride;
02513           }
02514           result(column) = columnMax;
02515         }
02516         break;
02517       case 1:
02518         result.reinit(array0.rows());
02519         for(size_t row = 0; row < array0.rows(); ++row) {
02520           const Type* dataPtr = array0.data(row, 0);
02521           Type rowMax = *dataPtr;
02522           for(size_t column = 0; column < array0.columns(); ++column) {
02523             if(comparator(*dataPtr, rowMax)) {
02524               rowMax = *dataPtr;
02525             }
02526             ++dataPtr;
02527           }
02528           result(row) = rowMax;
02529         }
02530         break;
02531       default:
02532         std::ostringstream message;
02533         message << "Axis " << axis << " is invalid for an Array2D.";
02534         DLR_THROW3(IndexException, "axisMinimum(const Array2D&, size_t, ...)",
02535                    message.str().c_str());
02536         break;
02537       }
02538       return result;  
02539     }
02540 
02541 
02542     // This function returns an Array1D in which each element has the
02543     // sum of one row or column of the input Array2D.
02544     template <class Type>
02545     inline Array1D<typename NumericTraits<Type>::SumType>
02546     axisSum(const Array2D<Type>& array0, size_t axis)
02547     {
02548       return axisSum(array0, axis,
02549                      type_tag<typename NumericTraits<Type>::SumType>());
02550     }
02551 
02552     // This function returns an Array1D in which each element has the
02553     // sum of one row or column of the input Array2D.
02554     template <class Type, class ResultType>
02555     inline Array1D<ResultType>
02556     axisSum(const Array2D<Type>& array0, size_t axis, type_tag<ResultType>)
02557     {
02558       return axisSum(array0, axis, type_tag<ResultType>(),
02559                      static_cast<ResultType>(0), std::plus<ResultType>());
02560     }
02561 
02562     // This function returns an Array1D in which each element has the
02563     // sum of one row or column of the input Array2D.
02564     template <class Type, class ResultType, class Functor>
02565     Array1D<ResultType>
02566     axisSum(const Array2D<Type>& array0, size_t axis, type_tag<ResultType>,
02567             const ResultType& initialValue, Functor adder)
02568     {
02569       Array1D<ResultType> result;
02570       switch(axis) {
02571       case 0:
02572         result.reinit(array0.columns());
02573         for(size_t column = 0; column < array0.columns(); ++column) {
02574           ResultType columnSum = initialValue;
02575           const Type* dataPtr = array0.data(0, column);
02576           size_t stride = array0.columns();
02577           for(size_t row = 0; row < array0.rows(); ++row) {
02578             columnSum = adder(columnSum, *dataPtr);
02579             dataPtr += stride;
02580           }
02581           result(column) = columnSum;
02582         }
02583         break;
02584       case 1:
02585         result.reinit(array0.rows());
02586         for(size_t row = 0; row < array0.rows(); ++row) {
02587           ResultType rowSum = initialValue;
02588           const Type* dataPtr = array0.data(row, 0);
02589           for(size_t column = 0; column < array0.columns(); ++column) {
02590             rowSum = adder(rowSum, *dataPtr);
02591             ++dataPtr;
02592           }
02593           result(row) = rowSum;
02594         }
02595         break;
02596       default:
02597         std::ostringstream message;
02598         message << "Axis " << axis << " is invalid for an Array2D.";
02599         DLR_THROW3(IndexException, "axisSum(const Array2D&, size_t, ...)",
02600                    message.str().c_str());
02601         break;
02602       }
02603       return result;  
02604     }
02605 
02606     // columnIndices(rows, columns): Returns an Array2D in which each
02607     // element contains the index of its column.
02608     template <class Type>
02609     Array2D<Type>
02610     columnIndices(size_t rows, size_t columns, type_tag<Type>)
02611     {
02612       Array2D<Type> returnValue(rows, columns);
02613       Array1D<Type> modelRow = range(static_cast<Type>(0),
02614                                      static_cast<Type>(columns),
02615                                      static_cast<Type>(1));
02616       for(size_t row=0; row < rows; ++row) {
02617         std::copy(modelRow.begin(), modelRow.end(), returnValue.data(row, 0));
02618       }
02619       return returnValue;
02620     }
02621 
02622     // This function selects those elements of an input Array1D which
02623     // correspond to "true" values of a mask Array1D, and returns an
02624     // Array1D containing only those elements.
02625     template <class Type0, class Type1>
02626     inline Array1D<Type1>
02627     compress(const Array1D<Type0>& condition,
02628              const Array1D<Type1>& input)
02629     {
02630       size_t numTrue = count(condition);
02631       return compress(condition, input, numTrue);
02632     }
02633 
02634     // This function behaves in exactly the same way as compress(const
02635     // Array1D&, const Array1D&), above, but it permits the user to
02636     // specify the number of true elements in the condition array.
02637     template <class Type0, class Type1>
02638     Array1D<Type1>
02639     compress(const Array1D<Type0>& condition,
02640              const Array1D<Type1>& input,
02641              size_t numTrue)
02642     {
02643       if(condition.size() != input.size()) {
02644         std::ostringstream message;
02645         message << "Condition and input arguments must have the same "
02646                 << "size, but condition has size = " << condition.size()
02647                 << ", while input has size = " << input.size() << ".";
02648         DLR_THROW3(ValueException,
02649                    "compress(const Array1D&, const Array1D&, size_t)",
02650                    message.str().c_str());
02651       }
02652       Array1D<Type1> result(numTrue);
02653       // copy_mask(input.begin(), input.end(), condition.begin(),
02654       //           result.begin());
02655       //
02656       // Hmm... copy_mask was previously defined in dlrLib3 as follows:
02657       //
02658       // template <class In0, class In1, class Out>
02659       // Out copy_mask(In0 first, In0 last, In1 mask, Out res)
02660       // {
02661       //   while(first != last) {
02662       //     if(*mask) {
02663       //       *res++ = *first;
02664       //     }
02665       //     ++mask;
02666       //     ++first;
02667       //   }
02668       //   return res;
02669       // }
02670 
02671       typename Array1D<Type1>::const_iterator first = input.begin();
02672       typename Array1D<Type1>::const_iterator last = input.end();
02673       typename Array1D<Type0>::const_iterator mask = condition.begin();
02674       typename Array1D<Type1>::iterator target = result.begin();
02675       while(first != last) {
02676         if(*mask) {
02677           *(target++) = *first;
02678         }
02679         ++mask;
02680         ++first;
02681       }
02682 
02683       return result;
02684     }
02685 
02686     // This element counts the number of elements of the input array
02687     // which evaluate to true, and returns that number.
02688     template <class Type>
02689     inline size_t
02690     count(const Array1D<Type>& x)
02691     {
02692       return std::count_if(x.begin(), x.end(), StaticCastFunctor<Type, bool>());
02693     }
02694 
02695     // This function computes the cross product of two Vector3D
02696     // instances.
02697     inline Vector3D
02698     cross(const Vector3D& vector0, const Vector3D& vector1) {
02699       return Vector3D((vector0.y() * vector1.z()) - (vector0.z() * vector1.y()),
02700                       (vector0.z() * vector1.x()) - (vector0.x() * vector1.z()),
02701                       (vector0.x() * vector1.y()) - (vector0.y() * vector1.x()));
02702     }
02703 
02704     // This function computes the inner product of two input arrays.
02705     // The computation is done using the ProductType specified by
02706     // the appropriate NumericTraits class.
02707     template <class Type>
02708     inline typename NumericTraits<Type>::ProductType
02709     dot(const Array1D<Type>& x, const Array1D<Type>& y)
02710     {
02711       return dot(x, y, type_tag<typename NumericTraits<Type>::ProductType>());
02712     }
02713 
02714     // This function computes the inner product of two input arrays, and
02715     // allows the user to control which type is used to do the
02716     // calculation.
02717     template <class Type0, class Type1, class Type2>
02718     inline Type2
02719     dot(const Array1D<Type0>& x, const Array1D<Type1>& y, type_tag<Type2>)
02720     {
02721       if(x.size() != y.size()) {
02722         std::ostringstream message;
02723         message << "Input arguments must have matching sizes, but x.size() == "
02724                 << x.size() << " and y.size() == " << y.size() << "."
02725                 << std::endl;
02726         DLR_THROW3(ValueException, "dot()", message.str().c_str());
02727       }
02728       return std::inner_product(x.begin(), x.end(), y.begin(),
02729                                 static_cast<Type2>(0));
02730     }
02731 
02732     // This function computes the inner product of two Vector2D instances.
02733     inline double
02734     dot(const Vector2D& vector0, const Vector2D& vector1)
02735     {
02736       return vector0.x() * vector1.x() + vector0.y() * vector1.y();
02737     }
02738 
02739     // This function computes the inner product of two Vector3D instances.
02740     inline double
02741     dot(const Vector3D& vector0, const Vector3D& vector1)
02742     {
02743       return (vector0.x() * vector1.x() + vector0.y() * vector1.y()
02744               + vector0.z() * vector1.z());
02745     }
02746 
02747     // This function computes the matrix X such that A * x = X * vec(A).
02748     template <class Type>
02749     Array2D<Type>
02750     equivalentMatrix(const Array1D<Type>& vector0, size_t rowsInMatrix)
02751     {
02752       Array2D<Type> XMatrix = zeros(rowsInMatrix, vector0.size() * rowsInMatrix,
02753                                     type_tag<Type>());
02754       for(size_t XRow = 0; XRow != rowsInMatrix; ++XRow) {
02755         for(size_t index0 = 0; index0 < vector0.length(); ++index0) {
02756           XMatrix(XRow, index0 * rowsInMatrix + XRow) = vector0(index0);
02757         }
02758       }
02759       return XMatrix;
02760     }
02761   
02762     // This function returns a 2D matrix with the specified shape in
02763     // which the elements on the diagonal are set to 1, and all other
02764     // elements are set to 0.
02765     template <class Type>
02766     Array2D<Type>
02767     identity(size_t rows, size_t columns, type_tag<Type>)
02768     {
02769       Array2D<Type> returnArray = zeros(rows, columns, type_tag<Type>());
02770       size_t rank = std::min(rows, columns);
02771       for(size_t index = 0; index < rank; ++index) {
02772         returnArray(index, index) = static_cast<Type>(1);
02773       } 
02774       return returnArray;
02775     }
02776 
02777 
02778     // This function returns an array in which each element is the
02779     // natural logarithm of the corresponding element of its input.
02780     template <class Type>
02781     Array1D<Type>
02782     ln(const Array1D<Type>& array0)
02783     {
02784       Array1D<Type> result(array0.size());
02785       // std::transform(array0.begin(), array0.end(), std::log);
02786       for(size_t index0 = 0; index0 < array0.size(); ++index0) {
02787         result[index0] = std::log(array0[index0]);      
02788       }
02789       return result;
02790     }
02791 
02792 
02793 //   // Strange troubles compiling these next two functions.
02794 //
02795 //   // This function returns an array in which each element is the
02796 //   // natural logarithm of the corresponding element of its input.
02797 //   template <>
02798 //   Array1D<float>
02799 //   ln(const Array1D<float>& array0)
02800 //   {
02801 //     Array1D<float> result(array0.size());
02802 //     std::transform(array0.begin(), array0.end(), std::logf);
02803 //     return result;
02804 //   }
02805 
02806 
02807 //   // This function returns an array in which each element is the
02808 //   // natural logarithm of the corresponding element of its input.
02809 //   template <>
02810 //   Array1D<long double>
02811 //   ln(const Array1D<long double>& array0)
02812 //   {
02813 //     Array1D<long double> result(array0.size());
02814 //     std::transform(array0.begin(), array0.end(), std::logl);
02815 //     return result;
02816 //   }
02817 
02818 
02819     // This function returns an array in which each element is the
02820     // natural logarithm of the corresponding element of its input.
02821     template <class Type>
02822     Array2D<Type>
02823     ln(const Array2D<Type>& array0)
02824     {
02825       Array2D<Type> result(array0.size());
02826       // std::transform(array0.begin(), array0.end(), std::log);
02827       for(size_t index0 = 0; index0 < array0.size(); ++index0) {
02828         result[index0] = std::log(array0[index0]);      
02829       }
02830       return result;
02831     }
02832 
02833 
02834     // This function returns an Array2D instance in which the value of
02835     // each element is the logical not of the corresponding element of
02836     // the input array.
02837     template <class Type>
02838     Array2D<Type>
02839     logicalNot(const Array2D<Type>& array0)
02840     {
02841       Array2D<Type> result(array0.rows(), array0.columns());
02842       std::transform(array0.begin(), array0.end(), result.begin(),
02843                      unaryComposeFunctor(StaticCastFunctor<bool, Type>(),
02844                                          std::logical_not<Type>()));
02845       return result;
02846     }
02847 
02848   
02849     // This function computes the magnitude of its input argument.
02850     template <class Type>
02851     inline Type
02852     magnitude(const Array1D<Type>& array0)
02853     {
02854       return static_cast<Type>(std::sqrt(magnitudeSquared(array0)));
02855     }
02856 
02857   
02858     // This function computes the magnitude of its input argument.
02859     inline double
02860     magnitude(const Vector2D& vector0) {
02861       return std::sqrt(magnitudeSquared(vector0));
02862     }
02863 
02864   
02865     // This function computes the magnitude of its input argument.
02866     inline double
02867     magnitude(const Vector3D& vector0) {
02868       return std::sqrt(magnitudeSquared(vector0));
02869     }
02870 
02871 
02872     // This function computes the square of the magnitude of its input
02873     // argument.
02874     template <class Type>
02875     inline typename NumericTraits<Type>::ProductType
02876     magnitudeSquared(const Array1D<Type>& array0)
02877     {
02878       typedef typename NumericTraits<Type>::ProductType ProductType;
02879       return std::inner_product(array0.begin(), array0.end(),
02880                                 array0.begin(), static_cast<ProductType>(0));
02881     }
02882 
02883 
02884     // This function computes the square of the magnitude of its input
02885     // argument.
02886     inline double
02887     magnitudeSquared(const Vector2D& vector0) {
02888       return (vector0.x() * vector0.x() + vector0.y() * vector0.y());
02889     }
02890 
02891   
02892     // This function computes the square of the magnitude of its input
02893     // argument.
02894     inline double
02895     magnitudeSquared(const Vector3D& vector0) {
02896       return (vector0.x() * vector0.x() + vector0.y() * vector0.y()
02897               + vector0.z() * vector0.z());
02898     }
02899 
02900   
02901     // This function computes a vector * matrix product.  Assuming the
02902     // first argument, vector0, represents a column vector and the
02903     // second argument, matrix0, represents a 2D array, then this function
02904     // computes the product:
02905     //   vector0' * matrix0
02906     // Where the single quote indicates transpose.
02907     template <class Type>
02908     inline Array1D<typename NumericTraits<Type>::ProductType>
02909     matrixMultiply(const Array1D<Type>& vector0, const Array2D<Type>& matrix0)
02910     {
02911       return matrixMultiply(
02912         vector0, matrix0, type_tag<typename NumericTraits<Type>::ProductType>());
02913     }
02914 
02915     // This function computes a vector * matrix product just like
02916     // matrixMultiply(const Array1D<Type>&, const Array2D<Type>&), above.
02917     // This function differs in that the element type of the return
02918     // value is set explicitly using a third argument.
02919     template <class Type0, class Type1, class Type2>
02920     Array1D<Type2>
02921     matrixMultiply(const Array1D<Type0>& vector0, const Array2D<Type0>& matrix0,
02922                    type_tag<Type2>)
02923     {
02924       if(vector0.size() != matrix0.rows()) {
02925         std::ostringstream message;
02926         message << "Can't left-multiply a "
02927                 << matrix0.rows() << " x " << matrix0.columns()
02928                 << " matrix by a " << vector0.size() << " element vector\n";
02929         DLR_THROW(ValueException, "matrixMultiply()", message.str().c_str());
02930       }
02931       Array1D<Type2> result = zeros(matrix0.columns(), type_tag<Type2>());
02932       size_t index = 0;
02933       for(size_t row = 0; row < matrix0.rows(); ++row) {
02934         for(size_t column = 0; column < matrix0.columns(); ++column) {
02935           result[column] += (static_cast<Type2>(vector0[row])
02936                              * static_cast<Type2>(matrix0[index]));
02937           ++index;
02938         }
02939       }
02940       return result;
02941     }
02942 
02943     // This function computes a matrix * vector product.  Assuming the
02944     // first argument, matrix0, represents a matrix, and the and the
02945     // second argument, vector0, represents a column vector, then this
02946     // function computes the product:
02947     //  matrix0 * vector0
02948     template <class Type>
02949     inline Array1D<typename NumericTraits<Type>::ProductType>
02950     matrixMultiply(const Array2D<Type>& matrix0, const Array1D<Type>& vector0)
02951     {
02952       return matrixMultiply(
02953         matrix0, vector0, type_tag<typename NumericTraits<Type>::ProductType>());
02954     }
02955 
02956 
02957     // This function computes a matrix * vector product just like
02958     // matrixMultiply(const Array2D<Type>&, const Array1D<Type>&), above.
02959     // This function differs in that the element type of the return
02960     // value is set explicitly using a third argument.
02961     template <class Type0, class Type1, class Type2>
02962     Array1D<Type2>
02963     matrixMultiply(const Array2D<Type0>& matrix0, const Array1D<Type1>& vector0,
02964                    type_tag<Type2>)
02965     {
02966       if(vector0.size() != matrix0.columns()) {
02967         std::ostringstream message;
02968         message << "matrixMultiply() -- can't right-multiply a "
02969                 << matrix0.rows() << " x " << matrix0.columns()
02970                 << " matrix by a " << vector0.size() << " element vector\n";
02971         DLR_THROW(ValueException, "matrixMultiply()", message.str().c_str());
02972       }
02973       Array1D<Type2> result(matrix0.rows());
02974       for(size_t row = 0; row < matrix0.rows(); ++row) {
02975         result[row] = dot(vector0, matrix0.row(row), type_tag<Type2>());
02976       }
02977       return result;
02978     }
02979 
02980     // This function computes a matrix * matrix product.  That is,
02981     // the elements of the resulting array are the dot products of the
02982     // rows of the first argument with the columns of the second argument.
02983     template <class Type>
02984     inline Array2D<typename NumericTraits<Type>::ProductType>
02985     matrixMultiply(const Array2D<Type>& matrix0, const Array2D<Type>& matrix1)
02986     {
02987       return matrixMultiply(
02988         matrix0, matrix1, type_tag<typename NumericTraits<Type>::ProductType>());
02989     }
02990     
02991     // This function computes a matrix * matrix product, just like
02992     // matrixMultiply(const Array2D<Type>&, const Array2D<Type>&), above.
02993     // This function differs in that the element type of the return
02994     // value is set explicitly using a third argument.
02995     template <class Type0, class Type1, class Type2>
02996     Array2D<Type2>
02997     matrixMultiply(const Array2D<Type0>& matrix0, const Array2D<Type1>& matrix1,
02998                    type_tag<Type2>)
02999     {
03000       if(matrix1.rows() != matrix0.columns()) {
03001         std::ostringstream message;
03002         message << "matrixMultiply() -- can't left-multiply a "
03003                 << matrix1.rows() << " x " << matrix1.columns()
03004                 << " matrix by a "
03005                 << matrix0.rows() << " x " << matrix0.columns()
03006                 << " matrix\n";
03007         DLR_THROW(ValueException, "matrixMultiply()", message.str().c_str());
03008       }
03009       Array2D<Type2> result = zeros(matrix0.rows(), matrix1.columns(),
03010                                     type_tag<Type2>());
03011       for(size_t resultRow = 0; resultRow < result.rows(); ++resultRow) {
03012         for(size_t resultColumn = 0; resultColumn < result.columns();
03013             ++resultColumn) {
03014           for(size_t index = 0; index < matrix0.columns(); ++index) {
03015             result(resultRow, resultColumn) +=
03016               (static_cast<Type2>(matrix0(resultRow, index))
03017                * static_cast<Type2>(matrix1(index, resultColumn)));
03018           }
03019         }
03020       }
03021       return result;
03022     }
03023 
03024     // This function returns a copy of the largest element in the input
03025     // Array1D instance.
03026     template <class Type>
03027     inline Type
03028     maximum(const Array1D<Type>& array0)
03029     {
03030       return maximum(array0, std::less<Type>());
03031     }
03032 
03033     // This function returns a copy of the largest element in the input
03034     // Array1D instance, where largeness is defined by the return value
03035     // of the second argument.
03036     template <class Type, class Functor>
03037     Type
03038     maximum(const Array1D<Type>& array0, Functor comparator)
03039     {
03040       if(array0.size() == 0) {
03041         DLR_THROW3(ValueException, "maximum()",
03042                    "Can't find the maximum element of an empty array.");
03043       }
03044       return *std::max_element(array0.begin(), array0.end(), comparator);
03045     }
03046 
03047 
03048     // This function computes the average value, or geometric mean, of
03049     // the elements of input sequence.
03050     template <class Iterator, class Type>
03051     Type
03052     mean(const Iterator& beginIter, const Iterator& endIter)
03053     {
03054       Type meanValue;
03055       size_t count = 0;
03056       while(beginIter != endIter) {
03057         meanValue += *beginIter;
03058         ++count;
03059         ++beginIter;
03060       }
03061       return meanValue / count;
03062     }
03063 
03064     
03065     // This function computes the average value, or geometric mean, of
03066     // the elements of its argument.
03067     template <class Type>
03068     inline double
03069     mean(const Array1D<Type>& array0)
03070     {
03071       if(array0.size() == 0) {
03072         DLR_THROW3(ValueException, "mean()",
03073                    "Can't find the mean of an empty array.");
03074       }
03075       NumericTypeConversionFunctor<typename NumericTraits<Type>::SumType,
03076         Type> functor;
03077       return functor(
03078         mean(array0, type_tag<typename NumericTraits<Type>::SumType>()));
03079     }
03080   
03081 
03082     // This function computes the average value, or geometric mean, of
03083     // the elements of its argument, and allows the user to specify the
03084     // precision with which the computation is carried out.
03085     template <class Type0, class Type1>
03086     inline Type1
03087     mean(const Array1D<Type0>& array0, type_tag<Type1>)
03088     {
03089       return sum(array0, type_tag<Type1>()) / static_cast<Type1>(array0.size());
03090     }
03091   
03092 
03093     // This function estimates the mean and covariance of a set of
03094     // vectors, which are represented by the rows (or columns) of the
03095     // input 2D array.
03096     template <class Type>
03097     void
03098     getMeanAndCovariance(const Array2D<Type>& sampleArray,
03099                          Array1D<double>& meanArray,
03100                          Array2D<double>& covarianceArray,
03101                          size_t majorAxis)
03102     {
03103       // Check input.
03104       if(sampleArray.size() == 0) {
03105         meanArray.reinit(0);
03106         covarianceArray.reinit(0, 0);
03107         return;
03108       }
03109 
03110       // Compute number of samples and sample dimensionality.
03111       size_t dimensionality;
03112       size_t numberOfSamples;
03113       if(majorAxis == 0) {
03114         dimensionality = sampleArray.columns();
03115         numberOfSamples = sampleArray.rows();
03116       } else {
03117         dimensionality = sampleArray.rows();
03118         numberOfSamples = sampleArray.columns();
03119       }
03120       
03121       // Now compute the mean value of the sample points.
03122       // For efficiency, we simultaneously compute covariance.
03123       // We make use of the identity:
03124       // 
03125       //   covariance = E[(x - u)*(x - u)^T] = E[x * x^T] - u * u^T
03126       // 
03127       // where E[.] denotes expected value and u is the mean.
03128       //
03129       // Note that the sample mean is an unbiased estimator for u, but
03130       // substituting the sample mean for u in the covariance equation
03131       // gives a biased estimator of covariance.  We resolve this by
03132       // using the unbiased estimator:
03133       //
03134       //   covariance = (1/(N-1))sum(x * x^T) - (N/(N-1)) * uHat * uHat^T
03135       //
03136       // where uHat is the sample mean.
03137 
03138       meanArray.reinit(dimensionality);
03139       meanArray = 0.0;
03140       covarianceArray.reinit(dimensionality, dimensionality);
03141       covarianceArray = 0.0;
03142       typename Array2D<Type>::const_iterator sampleIterator =
03143         sampleArray.begin();
03144 
03145       if(majorAxis == 0) {
03146         for(size_t rowIndex = 0; rowIndex < sampleArray.rows(); ++rowIndex) {
03147           for(size_t columnIndex = 0; columnIndex < sampleArray.columns();
03148               ++columnIndex) {
03149             // Update accumulator for mean.
03150             meanArray[columnIndex] += *sampleIterator;
03151 
03152             // Update accumulator for covariance.  We only compute the top
03153             // half of the covariance matrix for now, since it's symmetric.
03154             typename Array2D<Type>::const_iterator sampleIterator2 =
03155               sampleIterator;
03156             for(size_t covarianceIndex = columnIndex;
03157                 covarianceIndex < dimensionality;
03158                 ++covarianceIndex) {
03159               // Note(xxx): Should fix this to run faster.
03160               covarianceArray(columnIndex, covarianceIndex) +=
03161                 *sampleIterator * *sampleIterator2;
03162               ++sampleIterator2;
03163             }
03164             ++sampleIterator;
03165           }
03166         }
03167       } else {
03168         for(size_t rowIndex = 0; rowIndex < sampleArray.rows(); ++rowIndex) {
03169           for(size_t columnIndex = 0; columnIndex < sampleArray.columns();
03170               ++columnIndex) {
03171             // Update accumulator for mean.
03172             meanArray[rowIndex] += *sampleIterator;
03173 
03174             // Update accumulator for covariance.  We only compute the top
03175             // half of the covariance matrix for now, since it's symmetric.
03176             typename Array2D<Type>::const_iterator sampleIterator2 =
03177               sampleIterator;
03178             for(size_t covarianceIndex = rowIndex;
03179                 covarianceIndex < dimensionality;
03180                 ++covarianceIndex) {
03181               // Note(xxx): Should fix this to run faster.
03182               covarianceArray(rowIndex, covarianceIndex) +=
03183                 *sampleIterator * *sampleIterator2;
03184               sampleIterator2 += numberOfSamples;
03185             }
03186             ++sampleIterator;
03187           }
03188         }
03189       }
03190     
03191       // Finish up the computation of the mean.
03192       meanArray /= static_cast<double>(numberOfSamples);
03193 
03194       // Finish up the computation of the covariance matrix.
03195       for(size_t index0 = 0; index0 < dimensionality; ++index0) {
03196         for(size_t index1 = index0; index1 < dimensionality; ++index1) {
03197           // Add correction to the top half of the covariance matrix.
03198           covarianceArray(index0, index1) -=
03199             numberOfSamples * meanArray[index0] * meanArray[index1];
03200           covarianceArray(index0, index1) /= (numberOfSamples - 1);
03201 
03202           // And copy to the bottom half.
03203           if(index0 != index1) {
03204             covarianceArray(index1, index0) = covarianceArray(index0, index1);
03205           }
03206         }
03207       }
03208 
03209     }
03210   
03211                     
03212     // This function returns a copy of the smallest element in the input
03213     // Array1D instance.
03214     template <class Type>
03215     inline Type
03216     minimum(const Array1D<Type>& array0)
03217     {
03218       if(array0.size() == 0) {
03219         DLR_THROW3(ValueException, "minimum()",
03220                    "Can't find the minimum element of an empty array.");
03221       }
03222       return minimum(array0, std::less<Type>());
03223     }
03224 
03225     // This function returns a copy of the smallest element in the input
03226     // Array1D instance, where largeness is defined by the value of the
03227     // second argument.
03228     template <class Type, class Functor>
03229     Type
03230     minimum(const Array1D<Type>& array0, Functor comparator)
03231     {
03232       return *std::min_element(array0.begin(), array0.end(), comparator);
03233     }
03234 
03235 
03236     // This function uses the iterative method of Newton and Raphson to
03237     // search for a zero crossing of the supplied functor.
03238     template <class FUNCTOR>
03239     double newtonRaphson(double startPoint, FUNCTOR objectiveFunction,
03240                          double epsilon, size_t maxIterations)
03241     {
03242       double argument = startPoint;
03243       for(size_t count = 0; count < maxIterations; ++count) {
03244         double result = objectiveFunction(argument);
03245         if(std::fabs(result) < epsilon) {
03246           return argument;
03247         }
03248         double resultPrime = objectiveFunction.derivative(argument);
03249         if(resultPrime == 0.0) {
03250           DLR_THROW(ValueException, "newtonRaphson()", "Zero derivative.");
03251         }
03252         argument = argument - (result / resultPrime);
03253       }
03254       DLR_THROW(ValueException, "newtonRaphson()",
03255                 "Root finding failed to converge.");
03256       return 0.0;  // keep compiler happy
03257     }
03258 
03259     // This function computes the normalized correlation of two Array1D
03260     // arguments.
03261     template <class Type>
03262     inline double
03263     normalizedCorrelation(const Array1D<Type>& signal0,
03264                           const Array1D<Type>& signal1)
03265     {
03266       return normalizedCorrelation(signal0, signal1, type_tag<double>());
03267     }
03268 
03269     // This function is equivalent to normalizedCorrelation(const
03270     // Array1D&, const Array1D&), except that the computation is carried
03271     // out using the type specified by the third argument.
03272     template <class Type, class Type2>
03273     Type2
03274     normalizedCorrelation(const Array1D<Type>& signal0,
03275                           const Array1D<Type>& signal1,
03276                           type_tag<Type2>)
03277     {
03278       if(signal0.size() != signal1.size()) {
03279         DLR_THROW(ValueException, "normalizedCorrelation()",
03280                   "Input arrays must have the same size.");
03281       }
03282       Type2 oneOverN =
03283         static_cast<Type2>(1) / static_cast<Type2>(signal0.size());
03284       Type2 sum0 = static_cast<Type2>(0);
03285       Type2 sum1 = static_cast<Type2>(0);
03286       Type2 sum00 = static_cast<Type2>(0);
03287       Type2 sum01 = static_cast<Type2>(0);
03288       Type2 sum11 = static_cast<Type2>(0);
03289       typedef typename Array1D<Type>::const_iterator SignalIter;
03290       SignalIter iter0 = signal0.begin();
03291       SignalIter iter1 = signal1.begin();
03292       SignalIter end0 = signal0.end();
03293       while(iter0 != end0) {
03294         sum0 += *iter0;
03295         sum1 += *iter1;
03296         sum00 += (*iter0) * (*iter0);
03297         sum01 += (*iter0) * (*iter1);
03298         sum11 += (*iter1) * (*iter1);
03299         ++iter0;
03300         ++iter1;
03301       }
03302       Type2 numerator = sum01 - oneOverN * sum0 * sum1;
03303       Type2 denominator = std::sqrt((sum00 - oneOverN * sum0 * sum0)
03304                                     * (sum11 - oneOverN * sum1 * sum1));
03305       return numerator / denominator;
03306     }
03307 
03308     // This function returns an Array1D of the specified size and type
03309     // in which the value of every element is initialized to 1.
03310     template <class Type>
03311     inline Array1D<Type>
03312     ones(int size, type_tag<Type>)
03313     {
03314       Array1D<Type> result(size);
03315       result = 1;
03316       return result;
03317     }
03318 
03319     // This function returns an Array2D of the specified size and type
03320     // in which the value of every element is initialized to one.
03321     template <class Type>
03322     inline Array2D<Type>
03323     ones(int rows, int columns, type_tag<Type>)
03324     {
03325       Array2D<Type> result(rows, columns);
03326       result = 1;
03327       return result;
03328     }
03329 
03330     // This function computes the outer product of two input Array1D
03331     // instances. 
03332     template <class Type>
03333     inline Array2D<typename NumericTraits<Type>::ProductType>
03334     outerProduct(const Array1D<Type>& x, const Array1D<Type>& y)
03335     {
03336       return outerProduct(
03337         x, y, type_tag<typename NumericTraits<Type>::ProductType>());
03338     }
03339 
03340     // This function computes the outer product of two input Array1D
03341     // instances and allows the user to control which type is used to do the
03342     // computation.
03343     template <class Type0, class Type1, class Type2>
03344     Array2D<Type2>
03345     outerProduct(const Array1D<Type0>& x, const Array1D<Type1>& y,
03346                  type_tag<Type2>)
03347     {
03348       Array2D<Type2> result(x.size(), y.size());
03349       typename Array2D<Type2>::iterator runningIterator = result.begin();
03350       typename Array1D<Type1>::const_iterator yBegin = y.begin();
03351       typename Array1D<Type1>::const_iterator yEnd = y.end();
03352       for(size_t index = 0; index < x.size(); ++index) {
03353         std::transform(yBegin, yEnd, runningIterator,
03354                        std::bind2nd(std::multiplies<Type2>(), x[index]));
03355         runningIterator += y.size();
03356       }
03357       return result;
03358     }
03359 
03360     // This function returns an Array1D in which the first element has
03361     // value equal to argument "start," and each subsequent element has
03362     // value equal to the previous element plus argument "stride."
03363     template <class Type>
03364     Array1D<Type>
03365     range(Type start, Type stop, Type stride)
03366     {
03367       if(stride == 0) {
03368         DLR_THROW3(ValueException, "range(Type, Type, Type)",
03369                    "Argument \"stride\" must not be equal to 0.");
03370       }
03371       int length = static_cast<int>((stop - start) / stride);
03372       if(stride > 0) {
03373         if((length * stride) < (stop - start)) {      
03374           ++length;      
03375         }
03376       } else {
03377         if((length * stride) > (stop - start)) {
03378           ++length;      
03379         }
03380       }
03381       Array1D<Type> result(length);
03382       for(int index = 0; index < length; ++index) {
03383         result(index) = start;
03384         start += stride;
03385       }
03386       return result;
03387     }
03388   
03389 
03390     // This function computes the RMS (Root Mean Square) value of the
03391     // elements of its argument.
03392     template <class Type>
03393     inline Type
03394     rms(const Array1D<Type>& array0)
03395     {
03396       NumericTypeConversionFunctor<
03397         typename NumericTraits<Type>::SumType, Type> functor;
03398       return functor(rms(array0,
03399                          type_tag<typename NumericTraits<Type>::ProductType>()));
03400     }
03401 
03402     // This function computes the RMS (Root Mean Square) value of the
03403     // elements of its argument, and allows the user to specify the
03404     // precision with which the computation is carried out.
03405     template <class Type0, class Type1>
03406     Type1
03407     rms(const Array1D<Type0>& array0, type_tag<Type1>)
03408     {
03409       Type1 accumulator = 0;
03410       for(int index = 0; index < array0.size(); ++index) {
03411         Type1 element = static_cast<Type1>(array0[index]);
03412         accumulator += element * element;
03413       }
03414       return ::sqrt(accumulator / static_cast<Type1>(array0.size()));
03415     }
03416 
03417     // rowIndices(rows, columns): Returns an Array2D in which each
03418     // element contains the index of its row.
03419     template <class Type>
03420     Array2D<Type>
03421     rowIndices(size_t rows, size_t columns, type_tag<Type>)
03422     {
03423       Array2D<Type> returnValue(rows, columns);
03424       for(size_t row=0; row < rows; ++row) {
03425         Type* rowPtr = returnValue.data(row, 0);
03426         std::fill(rowPtr, rowPtr + columns, static_cast<Type>(row));
03427       }
03428       return returnValue;
03429     }
03430 
03431     // This function returns true if the two arrays have the same shape,
03432     // false otherwise.
03433     template <class Type0, class Type1>
03434     inline bool
03435     shapeMatch(const Array1D<Type0>& array0, const Array1D<Type1>& array1)
03436     {
03437       return array0.size() == array1.size();
03438     }
03439 
03440     // This function returns true if the two arrays have the same shape,
03441     // false otherwise.
03442     template <class Type0, class Type1>
03443     inline bool
03444     shapeMatch(const Array2D<Type0>& array0, const Array2D<Type1>& array1)
03445     {
03446       return ((array0.rows() == array1.rows())
03447               && (array0.columns() == array1.columns()));
03448     }
03449 
03450     // This function returns true if the two arrays have the same shape,
03451     // false otherwise.
03452     template <class Type0, class Type1>
03453     inline bool
03454     shapeMatch(const Array3D<Type0>& array0, const Array3D<Type1>& array1)
03455     {
03456       return ((array0.shape0() == array1.shape0())
03457               && (array0.shape1() == array1.shape1())
03458               && (array0.shape2() == array1.shape2()));            
03459     }
03460 
03461     // skewSymmetric(x): Returns a skew symmetric matrix X such
03462     // that matrixMultiply(X, y) = cross(x, y).
03463     template <class Type>
03464     inline Array2D<Type>
03465     skewSymmetric(const Array1D<Type>& vector0)
03466     {
03467       if(vector0.size() != 3) {
03468         std::ostringstream message;
03469         message << "Argument must have exactly 3 elements, but instead has "
03470                 << vector0.size() << "elements.";
03471         DLR_THROW(ValueException, "skewSymmetric()", message.str().c_str());
03472       }
03473       Array2D<Type> returnVal(3, 3);
03474       returnVal(0, 0) = 0;
03475       returnVal(0, 1) = -vector0(2);
03476       returnVal(0, 2) = vector0(1);
03477   
03478       returnVal(1, 0) = vector0(2);
03479       returnVal(1, 1) = 0;
03480       returnVal(1, 2) = -vector0(0);
03481 
03482       returnVal(2, 0) = -vector0(1);
03483       returnVal(2, 1) = vector0(0);
03484       returnVal(2, 2) = 0;
03485       return returnVal;
03486     }
03487 
03488 
03489     // This function computes the real roots of the quadratic polynomial
03490     // c0*x^2 + c1*x + c0 = 0.
03491     template <class Type>
03492     void
03493     solveQuadratic(Type c0, Type c1, Type c2,
03494                    Type& root0, Type& root1, bool& valid,
03495                    bool checkValidity)
03496     {
03497       Type ss = c1 * c1;
03498       ss -= (4.0 * c0 * c2);
03499       if(checkValidity) {
03500         valid = (ss >= 0.0);
03501         // s = numpy.choose(valid, (1.0, s))
03502         if(!valid) {
03503           ss = 1.0;
03504         }
03505       } else {
03506         valid = true;
03507       }
03508       Type rt = std::sqrt(ss);
03509       // sgn = numpy.greater_equal(b, 0.0)
03510       // rt = numpy.choose(sgn, (-rt, rt))
03511       if(c1 < 0.0) {
03512         rt *= -1;
03513       }
03514       Type qq = -0.5 * (rt + c1);
03515       root0 = qq / c0;
03516       root1 = c2 / qq;
03517     }
03518 
03519   
03520     // This function computes the standard deviation of a group of
03521     // scalar samples.
03522     template <class Type>
03523     inline double
03524     standardDeviation(const Array1D<Type>& array0)
03525     {
03526       return standardDeviation(array0, type_tag<double>());
03527     }
03528 
03529     // This function computes the standard deviation, of the elements of
03530     // its argument, and allows the user to specify the precision with
03531     // which the computation is carried out.
03532     template <class Type0, class Type1>
03533     inline Type1
03534     standardDeviation(const Array1D<Type0>& array0, type_tag<Type1>)
03535     {
03536       return ::sqrt(variance(array0, type_tag<Type1>()));
03537     }
03538 
03539     // This function computes the sum of all elements in the input
03540     // array.  The summation is done using the SumType specified by the
03541     // appropriate NumericTraits class.
03542     template <class Type>
03543     inline typename NumericTraits<Type>::SumType
03544     sum(const Array1D<Type>& array0)
03545     {
03546       return sum(array0, type_tag<typename NumericTraits<Type>::SumType>());
03547     }
03548 
03549     // This function computes the sum of all elements in the input
03550     // array, and allows the user to control which type is used to do the
03551     // summation.
03552     template <class Type, class Type2>
03553     Type2
03554     sum(const Array1D<Type>& array0, type_tag<Type2>)
03555     {
03556       return std::accumulate(array0.begin(), array0.end(),
03557                              static_cast<Type2>(0));
03558     }
03559 
03560 
03561     // This function computes the sum of those elements of its
03562     // argument which lie within a rectangular region of interest.
03563     template <class Type>
03564     inline typename NumericTraits<Type>::SumType
03565     sum(const Array2D<Type>& array0,
03566         const Index2D& upperLeftCorner,
03567         const Index2D& lowerRightCorner)
03568     {
03569       return sum(array0, upperLeftCorner, lowerRightCorner,
03570                  type_tag<typename NumericTraits<Type>::SumType>());
03571     }
03572       
03573     
03574     // This function computes the sum of those elements of its
03575     // argument which lie within a rectangular region of interest.
03576     template <class Type, class Type2>
03577     Type2
03578     sum(const Array2D<Type>& array0,
03579         const Index2D& upperLeftCorner,
03580         const Index2D& lowerRightCorner,
03581         type_tag<Type2> typeTag)
03582     {
03583       Type2 result = static_cast<Type2>(0);
03584       for(int row = upperLeftCorner.getRow();
03585           row < lowerRightCorner.getRow();
03586           ++row) {
03587         typename Array2D<Type>::const_iterator rowBegin = array0.rowBegin(row);
03588         result += std::accumulate(
03589           rowBegin + upperLeftCorner.getColumn(),
03590           rowBegin + lowerRightCorner.getColumn(),
03591           static_cast<Type2>(0));
03592       }
03593       return result;
03594     }
03595 
03596     
03597     // This function computes the standard deviation of a group of
03598     // scalar samples.
03599     template <class Type>
03600     inline double
03601     variance(const Array1D<Type>& array0)
03602     {
03603       return variance(array0, type_tag<double>());
03604     }
03605 
03606     // This function computes the standard deviation, of the elements of
03607     // its argument, and allows the user to specify the precision with
03608     // which the computation is carried out.
03609     template <class Type0, class Type1>
03610     inline Type1
03611     variance(const Array1D<Type0>& array0, type_tag<Type1>)
03612     {
03613       Type1 meanValue = mean(array0, type_tag<Type1>());
03614       Type1 accumulator = 0;
03615       for(size_t index0 = 0; index0 < array0.size(); ++index0) {
03616         Type1 offset = static_cast<Type1>(array0[index0]) - meanValue;
03617         accumulator += offset * offset;
03618       }
03619       return accumulator / static_cast<Type1>(array0.size());
03620     }
03621 
03622     // This function returns an Array1D of the specified size and type
03623     // in which the value of every element is zero.
03624     template <class Type>
03625     inline Array1D<Type>
03626     zeros(size_t size, type_tag<Type>)
03627     {
03628       Array1D<Type> result(size);
03629       result = 0;
03630       return result;
03631     }
03632 
03633     // This function returns an Array2D of the specified size and type
03634     // in which the value of every element is zero.
03635     template <class Type>
03636     inline Array2D<Type>
03637     zeros(size_t rows, size_t columns, type_tag<Type>)
03638     {
03639       Array2D<Type> result(rows, columns);
03640       result = 0;
03641       return result;
03642     }
03643 
03644 
03645     // This function returns an Array3D of the specified size and type
03646     // in which the value of every element is zero.
03647     template <class Type>
03648     inline Array3D<Type>
03649     zeros(size_t shape0, size_t shape1, size_t shape2, type_tag<Type>)
03650     {
03651       Array3D<Type> result(shape0, shape1, shape2);
03652       result = 0;
03653       return result;
03654     }
03655   
03656   } // namespace numeric
03657 
03658 } // namespace dlr
03659 
03660 #endif /* #ifndef _DLR_NUMERIC_UTILITIES_H_ */

Generated on Tue Jun 24 16:48:37 2008 for dlrUtilities Utility Library by  doxygen 1.5.5