arch/x86_64-rhel5-gcc41-opt/geninc/ndarray/ndarray.h

Go to the documentation of this file.
00001 #ifndef NDARRAY_NDARRAY_H
00002 #define NDARRAY_NDARRAY_H
00003 
00004 //--------------------------------------------------------------------------
00005 // File and Version Information:
00006 //      $Id: ndarray.h 6652 2013-08-13 18:19:30Z salnikov@SLAC.STANFORD.EDU $
00007 //
00008 // Description:
00009 //      Class ndarray.
00010 //
00011 //------------------------------------------------------------------------
00012 
00013 //-----------------
00014 // C/C++ Headers --
00015 //-----------------
00016 #include <algorithm>
00017 #include <functional>
00018 #include <numeric>
00019 #include <iterator>
00020 
00021 //----------------------
00022 // Base Class Headers --
00023 //----------------------
00024 #include "nd_elem_access.h"
00025 
00026 //-------------------------------
00027 // Collaborating Class Headers --
00028 //-------------------------------
00029 
00030 //------------------------------------
00031 // Collaborating Class Declarations --
00032 //------------------------------------
00033 
00034 //              ---------------------
00035 //              -- Class Interface --
00036 //              ---------------------
00037 
00038 /// @addtogroup ndarray
00039 
00040 /**
00041  *  @ingroup ndarray
00042  */
00043 namespace ndns {
00044 
00045   /**
00046    *   Enum defines assumed order of the element in memory. Values are used
00047    *   as parameters for constructors and reshape() method. By default methods
00048    *   assume C-style memory ordering where last index changes faster. If
00049    *   in-memory data has Fortran layout (first index changes faster) than
00050    *   one needs to provide Fortran as the last argument to the above methods.
00051    *   It is also possible to change strides to any other memory layout
00052    *   by using strides() method.
00053    */
00054   enum Order { C, Fortran };
00055 
00056 }
00057 
00058 /// @addtogroup ndarray_details
00059 
00060 /**
00061  *  @ingroup ndarray_details
00062  */
00063 namespace ndarray_details {
00064 
00065   // special destroyer for non-owned data
00066   template <typename ElemType>
00067   struct _no_delete {
00068     void operator()(ElemType*) const {}
00069   };
00070 
00071   // special destroyer for owned array data
00072   template <typename ElemType>
00073   struct _array_delete {
00074     void operator()(ElemType* ptr) const { delete [] ptr; }
00075   };
00076 
00077   // some template magic to drop const from type decl
00078   template <typename T>
00079   struct unconst { typedef T type; };
00080   template <typename T>
00081   struct unconst<const T> { typedef T type; };
00082 
00083 }
00084 
00085 /// @addtogroup ndarray
00086 
00087 /**
00088  *  @ingroup ndarray
00089  *
00090  *  @brief N-dimensional array class.
00091  *
00092  *  Ndarray (short for N-dimensional array) class provides high-level C++
00093  *  interface for multi-dimensional array data. This is a class template with
00094  *  two parameters - element type and array rank. Array dimensionality
00095  *  (rank) is fixed at compile time and cannot change. Actual dimensions and
00096  *  size of array are dynamic and can change (for example in assignment).
00097  *
00098  *  The type of the array elements is determined by the first template argument
00099  *  and it can be any regular C++ type of fixed size. There is a distinction
00100  *  between const and non-const template arguments. If non-const type is
00101  *  used for template argument (such as ndarray<int,2>) then the resulting
00102  *  ndarray is a modifiable object, one could use its methods to get access to
00103  *  array elements and modify them (through non-const references or pointers).
00104  *  On the other hand if template argument is a const type (e.g. ndarray<const int,2>)
00105  *  then array is non-modifiable, it only returns const pointers and references to
00106  *  the data which cannot be used to modify the data.
00107  *
00108  *  There are two essential characteristics of every array - array shape and strides.
00109  *  Array shape defines the size of every dimension of the array; shape is itself
00110  *  a 1-dimensional array of size @c NDim (ndarray rank). Shape of the array is set in
00111  *  the constructor and can be queried with @c shape() method. Strides define memory
00112  *  layout of the array data. By default (if you do not provide strides in constructor)
00113  *  ndarray assumes C-type memory layout (last index changes fastest) and
00114  *  calculates appropriate strides itself. One can provide non-standard strides
00115  *  for different (even disjoint) memory layouts. ndarray uses strides to calculate
00116  *  element offset w.r.t. first element of the array. For example for 3-dimensional
00117  *  array it finds an element as:
00118  *
00119  *    @code
00120  *    ndarr[i][j][k] = *(data + i*stride[0] + j*stride[1] * k*stride[2])
00121  *    @endcode
00122  *
00123  *  where @c data is a pointer to first array element. For C-type memory layout
00124  *  strides array is calculated from shape array as:
00125  *
00126  *    @code
00127  *    strides[NDim-1] = 1;
00128  *    for (i = NDim-1 .. 1) strides[i-1] = strides[i]*shape[i];
00129  *    @endcode
00130  *
00131  *  One can query the strides array with the @c strides() method which returns a pointer
00132  *  to the 1-dimensional array of @c NDim size.
00133  *
00134  *  Ndarray can be used to either provide access to the already existing data
00135  *  (which are not in the form of the ndarray), or to create new objects
00136  *  with newly allocated memory for array data. Ndarray transparently supports
00137  *  memory management of the data area, in most cases one should not care about
00138  *  how memory is allocated or deallocated. There are few different ways to
00139  *  construct ndarray instances which determine how ndarray manages its corresponding
00140  *  data:
00141  *
00142  *  1. from raw pointers:
00143  *     @code
00144  *     int* ptr = new int[100*100];
00145  *     unsigned int shape[2] = {100, 100};
00146  *     ndarray<int,2> array(ptr, shape);
00147  *     //or
00148  *     ndarray<int,2> array = make_ndarray(ptr, 100, 100);
00149  *     @endcode
00150  *
00151  *     In this case ndarray does not do anything special with the pointer that is
00152  *     passed to it, it is responsibility of the client code to make sure that
00153  *     memory is correctly deallocated if necessary and deallocation happens only after
00154  *     the last copy of ndarray is destroyed. Because of the potential problems it is
00155  *     not recommended anymore to make ndarrays from raw pointers.
00156  *
00157  *  2. internal memory allocation:
00158  *     @code
00159  *     unsigned int shape[2] = {100, 100};
00160  *     ndarray<int,2> array(shape);
00161  *     // or
00162  *     ndarray<int,2> array = make_ndarray<int>(100, 100);
00163  *     @endcode
00164  *
00165  *     In this case constructor allocates necessary space to hold array data. This
00166  *     space is automatically deallocated when the last copy of the ndarray pointing
00167  *     to that array data is destroyed. This is a preferred way to make ndarrays if
00168  *     you need to allocate new memory for your data.
00169  *
00170  *  3. from shared pointer (for advanced users):
00171  *     @code
00172  *     boost::shared_ptr<int> data = ...;
00173  *     unsigned int shape[2] = {100, 100}
00174  *     ndarray<int,2> array(data, shape);
00175  *     // or
00176  *     ndarray<int,2> array = make_ndarray(data, 100, 100);
00177  *     @endcode
00178  *
00179  *     In this case shared pointer defines memory management policy for the data, ndarray
00180  *     copies this pointers and shares array data through this pointer with all other
00181  *     clients. The memory will be deallocated (if necessary) when last copy of shared
00182  *     pointer disappears (including all copies in ndarray instances). Note that
00183  *     creating shared pointer for array data needs special care. One cannot just say:
00184  *     @code
00185  *     // DO NOT DO THIS, BAD THINGS WILL HAPPEN!
00186  *     boost::shared_ptr<int> data(new int[100*100]);
00187  *     @endcode
00188  *     as this will cause incorrect <tt>operator new</tt> be called when data is going to be
00189  *     deallocated. Special deleter object (or different way of constructing) is needed
00190  *     in this case, check boost.shared_ptr documentation.
00191  *
00192  *  The main method of accessing array elements is a traditional C-like square
00193  *  bracket syntax:
00194  *
00195  *    @code
00196  *    ndarray<int, 3> ndarr(...);
00197  *    int elem = ndarr[i][j][k];
00198  *    @endcode
00199  *
00200  *  Alternatively if the array indices are located in an array one can use @c at() method:
00201  *
00202  *    @code
00203  *    ndarray<int, 3> ndarr(...);
00204  *    unsigned idx[3] = {i, j, k};
00205  *    int elem = ndarr.at(idx);
00206  *    @endcode
00207  *
00208  *  One can modify elements of the array if array template type is non-const:
00209  *
00210  *    @code
00211  *    ndarray<int, 3> ndarr(...);
00212  *    ndarr[i][j][k] = 1000;
00213  *    @endcode
00214  *
00215  *  Additionally ndarray class provides STL-compatible iterators and usual methods
00216  *  @c begin(), @c end(), @c rbegin(), @c rend(). The iterators can be used with
00217  *  many standard algorithm. Note that iterators always scan for elements in the
00218  *  memory order from first (data()) to last (data()+size()) array element
00219  *  (iterators do not use strides and do not work with disjoint array memory).
00220  *
00221  *  Method @c size() returns the total number of elements in array.
00222  *
00223  *  Regular ndarray constructor take shape array (and optionally strides array).
00224  *  It is not always convenient to pass array dimensions as array elements. Few
00225  *  additional functions are provided which construct ndarray from dimensions
00226  *  provided via regular arguments, here are few examples of their use:
00227  *
00228  *    @code
00229  *    // Create 1-dim array of size 1048576
00230  *    int* data = ...;
00231  *    ndarray<int, 1> arr2d = make_ndarray(data, 1048576);
00232  *
00233  *    // Create 2-dim array of dimensions 1024x1024, allocate space for it
00234  *    ndarray<int, 2> arr2d = make_ndarray<int>(1024, 1024);
00235  *
00236  *    // Create 3-dim array of dimensions 4x512x512 from shared pointer
00237  *    boost::shared_ptr<int> shptr = ...;
00238  *    ndarray<int, 3> arr2d = make_ndarray(shptr, 4, 512, 512);
00239  *
00240  *    // Create non-modifiable array from constant data
00241  *    const int* cdata = ...;
00242  *    ndarray<const int, 1> arr2d = make_ndarray(cdata, 1048576);
00243  *    @endcode
00244  *
00245  *  This software was developed for the LCLS project.  If you use all or 
00246  *  part of it, please give an appropriate acknowledgment.
00247  *
00248  *  @version $Id: ndarray.h 6652 2013-08-13 18:19:30Z salnikov@SLAC.STANFORD.EDU $
00249  *
00250  *  @author Andy Salnikov
00251  */
00252 
00253 template <typename ElemType, unsigned NDim>
00254 class ndarray : public ndarray_details::nd_elem_access<ElemType, NDim> {
00255   typedef ndarray_details::nd_elem_access<ElemType, NDim> Super;
00256 public:
00257 
00258   typedef ElemType element;
00259   typedef element* iterator;
00260   typedef std::reverse_iterator<iterator> reverse_iterator;
00261   typedef size_t size_type;
00262   typedef unsigned shape_t;
00263   typedef int stride_t;
00264   typedef ndarray<typename ndarray_details::unconst<ElemType>::type, NDim> nonconst_ndarray;
00265 
00266   /// Default constructor makes an empty array
00267   ndarray () {}
00268 
00269   /**
00270    *  @brief Constructor that takes pointer to data and shape.
00271    *
00272    *  Optional third argument defines memory order of the elements, default is to
00273    *  assume C order (last index changes fastest). This argument determines how strides
00274    *  are calculated, strides can be changed later with strides() method.
00275    *
00276    *  @param[in] data   Pointer to data array
00277    *  @param[in] shape  Pointer to dimensions array, size of array is NDim, array data will be copied.
00278    *  @param[in] order  Memory order of the elements.
00279    */
00280   ndarray (ElemType* data, const shape_t* shape, ndns::Order order = ndns::C)
00281   {
00282     std::copy(shape, shape+NDim, Super::m_shape);
00283     _setStrides(order);
00284     Super::m_data = boost::shared_ptr<ElemType>(data, ndarray_details::_no_delete<ElemType>());
00285   }
00286 
00287   /**
00288    *  @brief Constructor that takes shared pointer to data and shape array.
00289    *
00290    *  Optional third argument defines memory order of the elements, default is to
00291    *  assume C order (last index changes fastest). This argument determines how strides
00292    *  are calculated, strides can be changed later with strides() method.
00293    *
00294    *  @param[in] data   Pointer to data array
00295    *  @param[in] shape  Pointer to dimensions array, size of array is NDim, array data will be copied.
00296    *  @param[in] order  Memory order of the elements.
00297    */
00298   ndarray (const boost::shared_ptr<ElemType>& data, const shape_t* shape, ndns::Order order = ndns::C)
00299   {
00300     std::copy(shape, shape+NDim, Super::m_shape);
00301     _setStrides(order);
00302     Super::m_data = data;
00303   }
00304 
00305   /**
00306    *  @brief Constructor that takes shape array and allocates necessary space for data.
00307    *
00308    *  After allocation the data in array is not initialized and will contain garbage.
00309    *  Optional second argument defines memory order of the elements, default is to
00310    *  assume C order (last index changes fastest). This argument determines how strides
00311    *  are calculated, strides can be changed later with strides() method.
00312    *
00313    *  @param[in] shape  Pointer to dimensions array, size of array is NDim, array data will be copied.
00314    *  @param[in] order  Memory order of the elements.
00315    */
00316   ndarray (const shape_t* shape, ndns::Order order = ndns::C)
00317   {
00318     std::copy(shape, shape+NDim, Super::m_shape);
00319     _setStrides(order);
00320     Super::m_data = boost::shared_ptr<ElemType>(new ElemType[size()], ndarray_details::_array_delete<ElemType>());
00321   }
00322 
00323   /**
00324    *  @brief Constructor from nd_elem_access_pxy instance.
00325    *
00326    *  This constructor is used for slicing of the original ndarray, proxy
00327    *  is returned from operator[] and you can make ndarray which is a slice
00328    *  of the original array from that proxy object. Both original array and
00329    *  this new instance will share the data.
00330    */
00331   ndarray (const ndarray_details::nd_elem_access_pxy<ElemType, NDim>& pxy)
00332   {
00333     Super::m_data = pxy.m_data;
00334     std::copy(pxy.m_shape, pxy.m_shape+NDim, Super::m_shape);
00335     std::copy(pxy.m_strides, pxy.m_strides+NDim, Super::m_strides);
00336   }
00337 
00338   /**
00339    *  @brief Copy constructor from other ndarray.
00340    *
00341    *  If the template argument (ElemType) is a const type (like <tt>const int</tt> then
00342    *  this constructor makes const ndarray from non-const, so for example one can write
00343    *  code which converts non-const array to const:
00344    *
00345    *  @code
00346    *  ndarray<int,3> arr1 = ...;
00347    *  ndarray<const int,3> arr2(arr1);
00348    *  @endcode
00349    *
00350    *  If template argument (ElemType) is non-const type then this is a regular copy
00351    *  constructor. It does not actually copy array data, in both cases data is shared
00352    *  between original array and new instance.
00353    */
00354   ndarray(const nonconst_ndarray& other)
00355     : Super(other)
00356   {
00357   }
00358 
00359   /// Assignment operator, data is never copied.
00360   ndarray& operator=(const nonconst_ndarray& other)
00361   {
00362     Super::operator=(other);
00363     return *this;
00364   }
00365 
00366   /// Assignment from nd_elem_access_pxy.
00367   ndarray& operator=(const ndarray_details::nd_elem_access_pxy<ElemType, NDim>& pxy)
00368   {
00369     Super::m_data = pxy.m_data;
00370     std::copy(pxy.m_shape, pxy.m_shape+NDim, Super::m_shape);
00371     std::copy(pxy.m_strides, pxy.m_strides+NDim, Super::m_strides);
00372     return *this;
00373   }
00374 
00375 
00376   /**
00377    *  @brief Array element access.
00378    *
00379    *  This method accepts the array of indices, size of the array is the number of
00380    *  dimensions. Alternative way to access elements in the array is to use regular
00381    *  operator[] inherited from nd_elem_access base class.
00382    */
00383   element& at(shape_t index[]) const {
00384     element* data = Super::m_data.get();
00385     for (unsigned i = 0; i != NDim; ++ i) {
00386       data += index[i]*Super::m_strides[i];
00387     }
00388     return *data;
00389   }
00390 
00391   /**
00392    *  Returns pointer to the beginning of the data array.
00393    */
00394   element* data() const { return Super::m_data.get(); }
00395 
00396   /**
00397    *  @brief Returns shape of the array.
00398    *
00399    *  Returns an array (or pointer to its first element) of the ndarray dimensions.
00400    */
00401   const shape_t* shape() const { return Super::m_shape; }
00402 
00403   /**
00404    *  @brief Returns array strides.
00405    *
00406    *  Returns an array (or pointer to its first element) of the ndarray strides.
00407    */
00408   const stride_t* strides() const { return Super::m_strides; }
00409 
00410   /**
00411    *  @brief Changes strides.
00412    *
00413    *  If array has a non-conventional memory layout it is possible to change
00414    *  the strides.
00415    *
00416    *  @param[in] strides  Pointer to new strides array, size of array is NDim, array data will be copied.
00417    */
00418   void strides(const stride_t* strides) {
00419     std::copy(strides, strides+NDim, Super::m_strides);
00420   }
00421 
00422   /**
00423    *  @brief Changes the shape of the array.
00424    *
00425    *  No checks are done on the size of the new array.
00426    *  Optional second argument defines memory order of the elements, default is to
00427    *  assume C order (last index changes fastest). This argument determines how strides
00428    *  are calculated, strides can be changed later with strides() method.
00429    *
00430    *  @param[in] shape  Pointer to dimensions array, size of array is NDim, array data will be copied.
00431    *  @param[in] order  Memory order of the elements.
00432    */
00433   void reshape(const shape_t* shape, ndns::Order order = ndns::C) {
00434     std::copy(shape, shape+NDim, Super::m_shape);
00435     _setStrides(order);
00436   }
00437 
00438 
00439   /// Returns total number of elements in array
00440   size_type size() const {
00441     return std::accumulate(Super::m_shape, Super::m_shape+NDim, size_type(1), std::multiplies<size_type>());
00442   }
00443 
00444   /// Returns true if array has no data
00445   bool empty() const { return not Super::m_data; }
00446 
00447   /// Returns iterator to the beginning of data, iteration is performed in memory order
00448   iterator begin() const { return Super::m_data.get(); }
00449 
00450   /// Returns iterator to the end of data
00451   iterator end() const { return Super::m_data.get() + size(); }
00452 
00453   /// Returns reverse iterators
00454   reverse_iterator rbegin() const { return reverse_iterator(end()); }
00455   reverse_iterator rend() const { return reverse_iterator(begin()); }
00456 
00457   /// swap contents of two arrays
00458   void swap(ndarray& other) {
00459     std::swap(Super::m_data, other.Super::m_data);
00460     std::swap_ranges(Super::m_shape, Super::m_shape+NDim, other.Super::m_shape);
00461     std::swap_ranges(Super::m_strides, Super::m_strides+NDim, other.Super::m_strides);
00462   }
00463 
00464   /**
00465    *  Make a deep copy of the array data, returns modifiable array.
00466    *
00467    *  Note that this does not work with disjoint arrays, use on your own risk.
00468    */
00469   nonconst_ndarray copy() const {
00470     nonconst_ndarray res(shape());
00471     res.strides(strides());
00472     std::copy(begin(), end(), res.begin());
00473     return res;
00474   }
00475 
00476 protected:
00477 
00478   // calculate strides from shape array given the assumed ordering
00479   void _setStrides(ndns::Order order) {
00480     if (order == ndns::C) {
00481       Super::m_strides[NDim-1] = 1;
00482       for (int i = int(NDim)-2; i >= 0; -- i) Super::m_strides[i] = Super::m_strides[i+1] * Super::m_shape[i+1];
00483     } else {
00484       Super::m_strides[0] = 1;
00485       for (unsigned i = 1; i < NDim; ++ i) Super::m_strides[i] = Super::m_strides[i-1] * Super::m_shape[i-1];
00486     }
00487   }
00488 
00489 private:
00490 
00491 };
00492 
00493 /// @ingroup ndarray
00494 /// Helper method to create an instance of 1-dimensional array from raw data pointer.
00495 /// Note there may be potential problems with memory management with raw pointers.
00496 template <typename ElemType>
00497 inline
00498 ndarray<ElemType, 1> 
00499 make_ndarray(ElemType* data, unsigned dim0)
00500 {
00501   unsigned shape[] = {dim0};
00502   return ndarray<ElemType, 1>(data, shape);
00503 }
00504 
00505 /// @ingroup ndarray
00506 /// Helper method to create an instance of 2-dimensional array from raw data pointer.
00507 /// Note there may be potential problems with memory management with raw pointers.
00508 template <typename ElemType>
00509 inline
00510 ndarray<ElemType, 2> 
00511 make_ndarray(ElemType* data, unsigned dim0, unsigned dim1)
00512 {
00513   unsigned shape[] = {dim0, dim1};
00514   return ndarray<ElemType, 2>(data, shape);
00515 }
00516 
00517 /// @ingroup ndarray
00518 /// Helper method to create an instance of 3-dimensional array from raw data pointer.
00519 /// Note there may be potential problems with memory management with raw pointers.
00520 template <typename ElemType>
00521 inline
00522 ndarray<ElemType, 3> 
00523 make_ndarray(ElemType* data, unsigned dim0, unsigned dim1, unsigned dim2)
00524 {
00525   unsigned shape[] = {dim0, dim1, dim2};
00526   return ndarray<ElemType, 3>(data, shape);
00527 }
00528 
00529 /// @ingroup ndarray
00530 /// Helper method to create an instance of 4-dimensional array from raw data pointer.
00531 /// Note there may be potential problems with memory management with raw pointers.
00532 template <typename ElemType>
00533 inline
00534 ndarray<ElemType, 4> 
00535 make_ndarray(ElemType* data, unsigned dim0, unsigned dim1, unsigned dim2, unsigned dim3)
00536 {
00537   unsigned shape[] = {dim0, dim1, dim2, dim3};
00538   return ndarray<ElemType, 4>(data, shape);
00539 }
00540 
00541 /// @ingroup ndarray
00542 /// Helper method to create an instance of 1-dimensional array.
00543 /// Memory for data is allocated internally in this case.
00544 template <typename ElemType>
00545 inline
00546 ndarray<ElemType, 1>
00547 make_ndarray(unsigned dim0)
00548 {
00549   unsigned shape[] = {dim0};
00550   return ndarray<ElemType, 1>(shape);
00551 }
00552 
00553 /// @ingroup ndarray
00554 /// Helper method to create an instance of 2-dimensional array.
00555 /// Memory for data is allocated internally in this case.
00556 template <typename ElemType>
00557 inline
00558 ndarray<ElemType, 2>
00559 make_ndarray(unsigned dim0, unsigned dim1)
00560 {
00561   unsigned shape[] = {dim0, dim1};
00562   return ndarray<ElemType, 2>(shape);
00563 }
00564 
00565 /// @ingroup ndarray
00566 /// Helper method to create an instance of 3-dimensional array.
00567 /// Memory for data is allocated internally in this case.
00568 template <typename ElemType>
00569 inline
00570 ndarray<ElemType, 3>
00571 make_ndarray(unsigned dim0, unsigned dim1, unsigned dim2)
00572 {
00573   unsigned shape[] = {dim0, dim1, dim2};
00574   return ndarray<ElemType, 3>(shape);
00575 }
00576 
00577 /// @ingroup ndarray
00578 /// Helper method to create an instance of 4-dimensional array.
00579 /// Memory for data is allocated internally in this case.
00580 template <typename ElemType>
00581 inline
00582 ndarray<ElemType, 4>
00583 make_ndarray(unsigned dim0, unsigned dim1, unsigned dim2, unsigned dim3)
00584 {
00585   unsigned shape[] = {dim0, dim1, dim2, dim3};
00586   return ndarray<ElemType, 4>(shape);
00587 }
00588 
00589 /// @ingroup ndarray
00590 /// Helper method to create an instance of 1-dimensional array from shared pointer.
00591 /// Shaed pointer defines memory management policy in this case.
00592 template <typename ElemType>
00593 inline
00594 ndarray<ElemType, 1>
00595 make_ndarray(const boost::shared_ptr<ElemType>& data, unsigned dim0)
00596 {
00597   unsigned shape[] = {dim0};
00598   return ndarray<ElemType, 1>(data, shape);
00599 }
00600 
00601 /// @ingroup ndarray
00602 /// Helper method to create an instance of 2-dimensional array from shared pointer.
00603 /// Shaed pointer defines memory management policy in this case.
00604 template <typename ElemType>
00605 inline
00606 ndarray<ElemType, 2>
00607 make_ndarray(const boost::shared_ptr<ElemType>& data, unsigned dim0, unsigned dim1)
00608 {
00609   unsigned shape[] = {dim0, dim1};
00610   return ndarray<ElemType, 2>(data, shape);
00611 }
00612 
00613 /// @ingroup ndarray
00614 /// Helper method to create an instance of 3-dimensional array from shared pointer.
00615 /// Shaed pointer defines memory management policy in this case.
00616 template <typename ElemType>
00617 inline
00618 ndarray<ElemType, 3>
00619 make_ndarray(const boost::shared_ptr<ElemType>& data, unsigned dim0, unsigned dim1, unsigned dim2)
00620 {
00621   unsigned shape[] = {dim0, dim1, dim2};
00622   return ndarray<ElemType, 3>(data, shape);
00623 }
00624 
00625 /// @ingroup ndarray
00626 /// Helper method to create an instance of 4-dimensional array from shared pointer.
00627 /// Shaed pointer defines memory management policy in this case.
00628 template <typename ElemType>
00629 inline
00630 ndarray<ElemType, 4>
00631 make_ndarray(const boost::shared_ptr<ElemType>& data, unsigned dim0, unsigned dim1, unsigned dim2, unsigned dim3)
00632 {
00633   unsigned shape[] = {dim0, dim1, dim2, dim3};
00634   return ndarray<ElemType, 4>(data, shape);
00635 }
00636 
00637 #include "nd_format.h"
00638 
00639 #endif // NDARRAY_NDARRAY_H

Generated on 19 Dec 2016 for PSDMSoftware by  doxygen 1.4.7