src/Index/SIndex.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  *
00007  * Visit http://people.web.psi.ch/adelmann/ for more details
00008  *
00009  ***************************************************************************/
00010 
00011 #ifndef SINDEX_H
00012 #define SINDEX_H
00013 
00014 // include files
00015 #include "Index/NDIndex.h"
00016 #include "Index/SOffset.h"
00017 #include "Index/LSIndex.h"
00018 #include "FieldLayout/FieldLayoutUser.h"
00019 #include "Utility/RefCounted.h"
00020 #include "Utility/Inform.h"
00021 
00022 #ifdef IPPL_STDSTL
00023 #include <vector>
00024 using std::vector;
00025 #else
00026 #include <vector.h>
00027 #endif
00028 
00029 #ifdef IPPL_USE_STANDARD_HEADERS
00030 #include <iostream>
00031 using namespace std;
00032 #else
00033 #include <iostream.h>
00034 #endif
00035 
00036 // forward declarations
00037 template <unsigned Dim> class FieldLayout;
00038 template <unsigned Dim> class SIndex;
00039 template <unsigned Dim, unsigned Brackets> class IndexedSIndex;
00040 template <unsigned Dim>
00041 ostream& operator<<(ostream&, const SIndex<Dim>&);
00042 
00043 /***********************************************************************
00044  * 
00045  * SIndex represents a set of single-point indices for a Field, which
00046  * are used to implement sparse-index operations.  The user creates an
00047  * SIndex object through a where statement or by just adding individual
00048  * points, and then performs operations using the SIndex object just as
00049  * is done with a regular Index object.  In that case, operations are
00050  * only performed on those elements of the LHS which are in the SIndex
00051  * list.  Stencil operations are represented by using SOffset objects
00052  * to indicate offsets from the SIndex indices.
00053  *
00054  * Initially, an SIndex object is empty; points must be added to it by
00055  * calling addIndex.  An SIndex has an offset, set (or changed) by
00056  * calling setOffset(const SOffset&).  Only indices for local vnodes are
00057  * stored in this object; adding other points will return an error flag.
00058  *
00059  * Constructing an SIndex requires a FieldLayout object, since SIndex
00060  * needs to know the range of index values for which is can store points,
00061  * and the location of vnodes.
00062  *
00063  * A note about offsets: the offset factor is used primarily to make
00064  * it possible to specify index offsets in expressions for stenciling
00065  * purposes.  The method for adding an offset to an SIndex is via the
00066  * + or - operators, e.g., A[si] = B[si + SOffset<Dim>(1,-1)], or via
00067  * the () operator, e.g., A[si] = B[si(1,-1)] (which means the same as
00068  * above).  Otherwise, the user should not specify an offset, and the
00069  * operations such as union, intersection, etc. implicitly assume that
00070  * the offset is zero for the LHS and the RHS.
00071  *
00072  ***********************************************************************/
00073 
00074 template <unsigned Dim>
00075 class SIndex : public FieldLayoutUser {
00076 
00077 public:
00078   //# public typedefs
00079   typedef vector< RefCountedP<LSIndex<Dim> > >  container_t;
00080   typedef unsigned int                          size_type;
00081   typedef typename container_t::iterator        iterator_iv;
00082   typedef typename container_t::const_iterator  const_iterator_iv;
00083   typedef typename container_t::size_type       size_type_iv;
00084   typedef typename LSIndex<Dim>::iterator       iterator_indx;
00085   typedef typename LSIndex<Dim>::const_iterator  const_iterator_indx;
00086 
00087   // default constructor: this requires the user to call 'initialize'
00088   // before any other actions are carried out with this SIndex
00089   SIndex();
00090 
00091   // constructor: requires a FieldLayout
00092   SIndex(FieldLayout<Dim>&);
00093 
00094   // copy constructor
00095   SIndex(const SIndex<Dim>&);
00096 
00097   // destructor: frees memory used to store indices, and check out from Layout
00098   virtual ~SIndex();
00099 
00100   // initialize the object, if it was constructed with the default
00101   // constructor
00102   void initialize(FieldLayout<Dim>&);
00103 
00104   // report if we need initialization
00105   bool needInitialize() const { return (Layout == 0); }
00106 
00107   // a templated operator= taking a PETE expression
00108   template<class T1>
00109   SIndex<Dim>& operator=(const PETE_Expr<T1>& rhs) {
00110     assign(*this, rhs);
00111     return *this;
00112   }
00113 
00114   // assignment operator, with another SIndex or SOffset object.  If an
00115   // NDIndex object is given, all the points in the NDIndex are used.
00116   SIndex<Dim>& operator=(const SIndex<Dim>&);
00117   SIndex<Dim>& operator=(const SOffset<Dim>&);
00118   SIndex<Dim>& operator=(const NDIndex<Dim>&);
00119 
00120   // intersection operator, with another SIndex or SOffset object.
00121   // intersected SIndexes must have the same layout; intersection with an
00122   // SOffset will leave this object with at most one point
00123   SIndex<Dim>& operator&=(const SIndex<Dim>&);
00124   SIndex<Dim>& operator&=(const SOffset<Dim>&);
00125   SIndex<Dim>& operator&=(const NDIndex<Dim>&);
00126 
00127   // union operator, with another SIndex or SOffset object.  This will
00128   // append the point if it is not already present.
00129   SIndex<Dim>& operator|=(const SIndex<Dim>&);
00130   SIndex<Dim>& operator|=(const SOffset<Dim>&);
00131   SIndex<Dim>& operator|=(const NDIndex<Dim>&);
00132 
00133   // add a new index point, specified as an Offset or as a single-point NDIndex
00134   // return success (this can fail if the point is outsize the field's domain)
00135   bool addIndex(const SOffset<Dim>&);
00136   bool addIndex(iterator_iv&, const SOffset<Dim>&);
00137   void addIndex(const NDIndex<Dim>&);
00138 
00139   // remove an index point, specified as an Offset or as a single-point NDIndex
00140   // return success (this can fail if the point is not on this node)
00141   bool removeIndex(const SOffset<Dim>&);
00142   bool removeIndex(iterator_iv&, const SOffset<Dim>&);
00143   void removeIndex(const NDIndex<Dim>&);
00144 
00145   // reserve storage space equal to the given fraction of the size of
00146   // each vnode.  if fraction=1.0, reserve storage for the entire vnode.
00147   void reserve(double = 1.0);
00148 
00149   // clear out the existing indices
00150   void clear();
00151 
00152   // get the offset for this sparse index.  You can change the offset by
00153   // retrieving it this way and then adding to it.
00154   SOffset<Dim>& getOffset() { return Offset; }
00155   const SOffset<Dim>& getOffset() const { return Offset; }
00156 
00157   // get the FieldLayout we are using
00158   FieldLayout<Dim>& getFieldLayout() const { return *Layout; };
00159 
00160   // change to using a new layout.
00161   void setFieldLayout(FieldLayout<Dim>&);
00162 
00163   // get or change the 'bounding box' domain of this SIndex
00164   const NDIndex<Dim> &getDomain() const { return BoundingBox; }
00165   void setDomain(const NDIndex<Dim> &ndi) { BoundingBox = ndi; }
00166 
00167   //
00168   // SIndex <--> SOffset operations
00169   //
00170 
00171   // add or subtract a given offset
00172   // SIndex<Dim>& operator+=(const SOffset<Dim>& so) {Offset+=so;return *this;}
00173   // SIndex<Dim>& operator-=(const SOffset<Dim>& so) {Offset-=so;return *this;}
00174   friend
00175   SIndex<Dim> operator+(const SIndex<Dim>& si, const SOffset<Dim>& so) {
00176     return SIndex(si, so);
00177   }
00178 
00179   friend
00180   SIndex<Dim> operator+(const SOffset<Dim> &so, const SIndex<Dim>& si) {
00181     return SIndex(si, so);
00182   }
00183 
00184   friend
00185   SIndex<Dim> operator+(const SIndex<Dim>& si, const int *so) {
00186     return SIndex(si, so);
00187   }
00188 
00189   friend
00190   SIndex<Dim> operator+(const int *so, const SIndex<Dim>& si) {
00191     return SIndex(si, so);
00192   }
00193 
00194   friend
00195   SIndex<Dim> operator-(const SIndex<Dim>& si, const SOffset<Dim>& so) {
00196     return SIndex(si, -so);
00197   }
00198 
00199   friend
00200   SIndex<Dim> operator-(const SOffset<Dim> &so, const SIndex<Dim>& si) {
00201     return SIndex(si, -so);
00202   }
00203 
00204   friend
00205   SIndex<Dim> operator-(const SIndex<Dim>& si, const int *so) {
00206     return SIndex(si, -SOffset<Dim>(so));
00207   }
00208 
00209   friend
00210   SIndex<Dim> operator-(const int *so, const SIndex<Dim>& si) {
00211     return SIndex(si, -SOffset<Dim>(so));
00212   }
00213 
00214   // () operators which make a copy of this SIndex with an extra offset.
00215   // These are functionally identical to the operator+, but provide a
00216   // nicer syntax.  That is, si(1,1) means  si + SOffset<Dim>(1,1)
00217   SIndex<Dim> operator()(int);
00218   SIndex<Dim> operator()(int,int);
00219   SIndex<Dim> operator()(int,int,int);
00220   SIndex<Dim> operator()(int,int,int,int);
00221   SIndex<Dim> operator()(int,int,int,int,int);
00222   SIndex<Dim> operator()(int,int,int,int,int,int);
00223   SIndex<Dim> operator()(const SOffset<Dim>&);
00224   SIndex<Dim> operator()(const int *);
00225 
00226   // operator[], which is used with Index or NDIndex objects to further
00227   // subset the data.  This will only work if the dimension of the Index
00228   // arguments + Brackets is <= Dim.  Otherwise, too many dimensions worth
00229   // of Index objects are being applied
00230   IndexedSIndex<Dim,1> operator[](const Index &);
00231 
00232   template<unsigned int Dim2>
00233   IndexedSIndex<Dim,Dim2> operator[](const NDIndex<Dim2> &ndi) {
00234     TAU_TYPE_STRING(taustr, CT(*this) + " (NDIndex)"); 
00235     TAU_PROFILE("SIndex::operator[]", taustr, TAU_SPARSE);
00236     
00237     CTAssert(Dim >= Dim2);
00238     NDIndex<Dim> dom;
00239     for (int i=0; i < Dim2; ++i)
00240       dom[i] = ndi[i];
00241     return IndexedSIndex<Dim,Dim2>(*this, dom);
00242   }
00243 
00244   //
00245   // SIndex <--> NDIndex operations
00246   //
00247 
00248   // convert from the given SOffset value to an NDIndex, with offset added
00249   void toNDIndex(const SOffset<Dim>&, NDIndex<Dim>&);
00250 
00251   //
00252   // container methods
00253   //
00254 
00255   // return begin/end iterators for the LSIndex container
00256   iterator_iv  begin_iv()      { return IndexList.begin(); }
00257   iterator_iv  end_iv()        { return IndexList.end(); }
00258   const_iterator_iv  begin_iv() const { return IndexList.begin(); }
00259   const_iterator_iv  end_iv()   const { return IndexList.end(); }
00260   size_type_iv size_iv() const { return IndexList.size(); }
00261 
00262   // return the total size, which is the sum of the individual sizes
00263   size_type_iv size() const;
00264 
00265   // return whether the given point is contained here
00266   bool hasIndex(const SOffset<Dim>&) const;
00267 
00268   //
00269   // virtual functions for FieldLayoutUser's
00270   //
00271 
00272   // Repartition onto a new layout
00273   virtual void Repartition(UserList *);
00274 
00275   // Tell this object that an object is being deleted
00276   virtual void notifyUserOfDelete(UserList *);
00277 
00278   //
00279   // I/O
00280   //
00281 
00282   // print out debugging info
00283   void printDebug(Inform&) const;
00284 
00285 private:
00286   // our FieldLayout, indicating the extent and distrib. of index space
00287   FieldLayout<Dim>* Layout;
00288 
00289   // our current offset; by default, this is zero.  We keep a special flag
00290   // to indicate whether it is zero or not.
00291   SOffset<Dim> Offset;
00292 
00293   // our 'bounding box', which is the region that is or should be iterated
00294   // over to determine what points are in this sparse index list.  By default,
00295   // this is the domain of the FieldLayout
00296   NDIndex<Dim> BoundingBox;
00297 
00298   // our list of indices for each local vnode
00299   container_t IndexList;
00300 
00301   // a special constructor, taking another SIndex and an Offset.  This
00302   // version is almost like a copy constructor, except that the given Offset
00303   // is added in to the offset from the copied SIndex.
00304   SIndex(const SIndex<Dim>&, const SOffset<Dim>&);
00305   SIndex(const SIndex<Dim>&, const int *);
00306 
00307   // set up our internal data structures from the constructor.  Assumes
00308   // the Layout and Offset have been set.
00309   void setup();
00310 };
00311 
00312 #include "Index/SIndex.cpp"
00313 
00314 #endif // SINDEX_H
00315 
00316 /***************************************************************************
00317  * $RCSfile: SIndex.h,v $   $Author: adelmann $
00318  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:27 $
00319  * IPPL_VERSION_ID: $Id: SIndex.h,v 1.1.1.1 2003/01/23 07:40:27 adelmann Exp $ 
00320  ***************************************************************************/

Generated on Mon Jan 16 13:23:49 2006 for IPPL by  doxygen 1.4.6