casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
LatticeStepper.h
Go to the documentation of this file.
00001 //# LatticeStepper.h:  provides 'natural' traversal, by cursor shape
00002 //# Copyright (C) 1994,1995,1996,1997,1998,1999,2000,2001
00003 //# Associated Universities, Inc. Washington DC, USA.
00004 //#
00005 //# This library is free software; you can redistribute it and/or modify it
00006 //# under the terms of the GNU Library General Public License as published by
00007 //# the Free Software Foundation; either version 2 of the License, or (at your
00008 //# option) any later version.
00009 //#
00010 //# This library is distributed in the hope that it will be useful, but WITHOUT
00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013 //# License for more details.
00014 //#
00015 //# You should have received a copy of the GNU Library General Public License
00016 //# along with this library; if not, write to the Free Software Foundation,
00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00018 //#
00019 //# Correspondence concerning AIPS++ should be addressed as follows:
00020 //#        Internet email: aips2-request@nrao.edu.
00021 //#        Postal address: AIPS++ Project Office
00022 //#                        National Radio Astronomy Observatory
00023 //#                        520 Edgemont Road
00024 //#                        Charlottesville, VA 22903-2475 USA
00025 //#
00026 //# $Id: LatticeStepper.h 20652 2009-07-06 05:04:32Z Malte.Marquarding $
00027 
00028 #ifndef LATTICES_LATTICESTEPPER_H
00029 #define LATTICES_LATTICESTEPPER_H
00030 
00031 //# Includes
00032 #include <casa/aips.h>
00033 #include <lattices/Lattices/LatticeNavigator.h>
00034 #include <lattices/Lattices/LatticeIndexer.h>
00035 #include <casa/Arrays/IPosition.h>
00036 
00037 
00038 namespace casa { //# NAMESPACE CASA - BEGIN
00039 
00040 // <summary>
00041 // Traverse a Lattice by cursor shape
00042 // </summary>
00043 
00044 // <use visibility=export>
00045 
00046 // <reviewed reviewer="Peter Barnes" date="1999/10/30" tests="tLatticeStepper.cc">
00047 // </reviewed>
00048 
00049 // <prerequisite>
00050 //   <li> <linkto class=LatticeNavigator> LatticeNavigator </linkto>
00051 // </prerequisite>
00052 
00053 // <etymology>
00054 // LatticeStepper is so-called because it performs the calculations
00055 // necessary to step through a Lattice.  The next position is always one
00056 // simple step forward from the current position.  The step-size is
00057 // calculated directly from the size of the LatticeIterator's cursor or
00058 // window.
00059 // </etymology>
00060 
00061 // <synopsis> 
00062 // When you wish to traverse a Lattice (say, a PagedArray or an Image) you
00063 // will usually create a LatticeIterator.  Once created, you must attach a
00064 // LatticeNavigator to the iterator. A LatticeStepper, is a concrete class
00065 // derived from the abstract LatticeNavigator that allows you to move
00066 // sequentially through the Lattice.
00067 // <p>
00068 // In constructing a LatticeStepper, you specify the Lattice shape and the
00069 // shape of the "cursor" used to step through the data. The cursor position
00070 // can be incremented or decremented to retrieve the next portion of the
00071 // Lattice.
00072 // The specified cursor shape can (and often will) have fewer dimensions
00073 // that the Lattice itself. For example if we have a 4-dimensional Lattice
00074 // with <src>latticeShape = IPosition(4,64,64,4,16)</src>, then specifying a
00075 // cursor of <src>cursorShape = IPosition(1,64)</src>, will step through the
00076 // hypercube row by row. When the cursor shape has fewer dimensions than the
00077 // Lattice degenerate dimensions are added to the end of the cursor so that
00078 // in the above example the specified cursor is assumed to mean
00079 // <src>cursorShape = IPosition(4,64,1,1,1)</src>. To access the data
00080 // spectrum by spectrum (assuming the last axis is the spectral axis), you
00081 // must use a 1-dimensional cursor of <src>IPosition(4,1,1,1,16)</src>. The
00082 // <src>cursorShape</src> function always returns a shape with as many
00083 // dimensions as the underlying Lattice.
00084 // <p>
00085 // It is an error (and an exception will be thrown) if the cursor has more
00086 // dimensions than the Lattice or if it is larger on any axis than the
00087 // Lattice shape.
00088 // <br>
00089 // Also the cursor shape on all axes must be less than or equal to the Lattice
00090 // shape on that axis. Otherwise an exception will be thrown. 
00091 // <p>
00092 // In principle cursor axes with length 1 are degenerate axes. They
00093 // are removed from the lattice cursor if the
00094 // <linkto class=LatticeIterator>LatticeIterator</linkto> cursor is accessed
00095 // using e.g. the <src>matrixCursor</src> function.
00096 // Using a special LatticeStepper constructor it is, however, possible
00097 // to specify which cursor axes with length 1 have to be treated as
00098 // normal axes. In that way one can be sure that a cursor is, for
00099 // example, always 2D, even if an axis happens to have length 1.
00100 // <srcblock>
00101 // IPosition latticeShape(4,20,16,1,4);
00102 // IPosition cursorAxes(2,1,2);
00103 // IPosition cursorShape(2,16,1);
00104 // IPosition axisPath;
00105 // LatticeStepper stepper(latticeShape, cursorShape,
00106 //                        cursorAxes, axisPath);
00107 // </srcblock>
00108 // This results in a cursor with shape [1,16,1,1]. The first and last
00109 // axis are degenerate, so the cursor can also be accessed using
00110 // <src>matrixCursor</src> (with shape [16,1]).
00111 // Note that the cursor shape could also be specified as [1,16,1,1].
00112 // <p>
00113 // The "path" of the cursor through the Lattice can be controlled by
00114 // specifying an axisPath during construction of the class. This is an
00115 // IPosition which has exactly as many elements as the Lattice
00116 // dimension. Each element must contain an integer between 
00117 // 0 -- Lattice_Dimension-1, and must be unique. For example,
00118 // <srcblock>
00119 // axisPath = IPosition(4,0,1,2,3) or
00120 // axisPath = IPosition(4,3,1,2,0) 
00121 // </srcblock>
00122 // are valid but
00123 // <srcblock>
00124 // axisPath = IPosition(4,1,2,3,4) or
00125 // axisPath = IPosition(4,0,1,1,3) 
00126 // </srcblock>
00127 // are not, given the latticeShape specified above. An exception is thrown
00128 // if the AxisPath is bad. 
00129 // <br>
00130 // The "axis path" defines which axis will be iterated through fastest as
00131 // the cursor moves through the Lattice. With the above mentioned
00132 // 4-dimensional Lattice and a single element cursor
00133 // (<src>cursorShape=IPosition(4,1,1,1,1)</src>) setting an
00134 // <src>axisPath=IPosition(4,0,1,2,3)</src> will move the cursor through all
00135 // the columns, and then onto the next row, and again through all the
00136 // columns in the second row. Once all the rows in the first plane have
00137 // been exhausted the cursor will then iterate to the next plane, and
00138 // eventually to the next spectral channel. If, however, the axisPath was
00139 // <src>axisPath=IPosition(4,3,0,1,2)</src> then the cursor would iterate
00140 // through each spectral channel first, before moving onto the next column in
00141 // the first row.
00142 // <p>
00143 // The cursor never changes dimensionality as it traverses the Lattice.  But it
00144 // may change shape if the cursor shape is not a factor of the Lattice
00145 // shape. A cursor shape is not a factor of the Lattice shape if the Lattice
00146 // shape is not an integer multiple of the cursor shape on all axes.
00147 // The integer multiplier need not to be the same for each axes.
00148 // For example, for a Lattice of shape [10,10,10] a cursor of shape [8,5,2]
00149 // is not a factor but one with a shape of [10,5,1] is.
00150 // <br>
00151 // When the cursor is not congruent with the Lattice moving the cursor through
00152 // the Lattice will sometimes result in part of the cursor hanging over the
00153 // edge of the Lattice. When this occurs the hangOver member function will
00154 // return True. What to do in these situtations is specified by the
00155 // hangOverPolicy enumerator.
00156 // <ol>
00157 // <li>
00158 // If the LatticeStepper::PAD option (the default) is used at construction time
00159 // the cursor shape does not change. The parts of the cursor that hang over the
00160 // edge of the Lattice are filled with a default value, usually zero, that is
00161 // defined by the particular LatticeIterator used.
00162 // <li>
00163 // If the LatticeStepper::RESIZE option is used at construction time the cursor
00164 // shape does change to a smaller value when near the edge of the Lattice so
00165 // that it is just big enough. For example with a Lattice shape of 10x10 and a
00166 // cursor of 8x8 the cursor shape will initally be 8x8, then resize to 2x8 on
00167 // the first step, then resize to 8x2 on the second step and finally resize to
00168 // 2x2. The hangover function will return True for the last three steps, even
00169 // though the cursor has resized.
00170 // </ol>
00171 // The portion of the Lattice that the cursor will traverse can be
00172 // restricted to a region defined by a top right corner, bottom left corner
00173 // and a step size. This is done using the <src>subSection</src> function,
00174 // which also resets the cursor position to the origin of the sub-Lattice.
00175 // The cursor shape will remain unchanged. It is no error when the cursor
00176 // shape exceeds the sub-Lattice shape (instead it is a hangover state).
00177 // <br>
00178 // If a sub-Lattice is defined then cursor positions relative
00179 // to the sub-Lattice origins can be obtained using the
00180 // <src>relativePosition</src> function rather than the
00181 // <src>position</src> function, which always returns positions relative to
00182 // the origin of the main Lattice.
00183 // <br>
00184 // To change the size of the sub-Lattice simply call the
00185 // <src>subSection</src> function again with a different trc, blc &
00186 // inc. This first clears the old sub-Lattice, then imposes the newly
00187 // specified one, and finally moves the cursor to the origin of the
00188 // new sub-Lattice.
00189 // </synopsis> 
00190 
00191 // <example>
00192 // This example is of a global function that will iterate through a
00193 // 4-dimensional Lattice. It is assumed that the axes are RA, Dec, Stokes &
00194 // Frequency, and it will calculate the average flux in the I polarization
00195 // on each frequency channel. Imagine it is passed a data set (ie. Lattice)
00196 // of size 256 x 256 x 4 x 1024. This corresponds to 1GByte of data. However
00197 // the iterator will page through this data using a cursor of size 256 x 256
00198 // (or 256kByte) and will only read (because of subsectioning) the relevant
00199 // quarter of the data set. It is usually a good idea to set up the axis
00200 // path as this is gives hints to data cache about which data to retrieve in
00201 // advance.
00202 // <srcblock>
00203 // void averageFluxByChannel(const Lattice<Float>& data)
00204 // {
00205 //   // for convenience, get the shape into a local variable
00206 //   IPosition latticeShape = data.shape();
00207 //   cout << "Data has shape: " << latticeShape << endl;
00208 // 
00209 //   // check that the data has 4 axes.
00210 //   DebugAssert(latticeShape.nelements() == 4, AipsError); 
00211 //     
00212 //   // specify the cursor, or window shape.  Here the cursor is a matrix 
00213 //   // that is the shape of the first plane of our Lattice.
00214 //   // For convenience, get the first two axis lengths into local vars
00215 //   uInt nCols = latticeShape(0);
00216 //   uInt nRows = latticeShape(1);
00217 //   IPosition cursorShape(2, nCols, nRows);
00218 // 
00219 //   // construct a stepper, which needs to know the shape of the lattice
00220 //   // and the shape of the iterator's cursor. By using cursorShape, which
00221 //   // is directly determined by the lattice's shape, we can be sure
00222 //   // that the cursor is a factor of the lattice, and thus that
00223 //   // all elements will be picked up efficiently during the traversal.
00224 //   // Because we will not be iterating through the stokes axis this axis
00225 //   // is made the slowest moving one. 
00226 //   IPosition axisPath(4, 0, 1, 3, 2)
00227 //   LatticeStepper stepper(latticeShape, cursorShape, axisPath);
00228 //
00229 //   // Subsection the stepper so that it only iterates through the I
00230 //   // Stokes parameter (assumed to be when the third axis is zero)
00231 //   uInt nFreqs = latticeShape(3);
00232 //   IPosition blc(4, 0, 0, 0, 0), trc(4, nCols-1, nRows-1, 0, nFreqs-1);
00233 //   stepper.subSection(blc, trc);
00234 //  
00235 //   // construct the iterator.  Since we only want to read the Data,
00236 //   // use the read-only class, which disallows writing back to the cursor
00237 //   // (and hence is more efficient).
00238 //   RO_LatticeIterator<Float> iterator(data, stepper);
00239 // 
00240 //   Vector<Float> spectrum(nFreqs);
00241 //   spectrum = 0.0;
00242 //   uInt channel = 0;
00243 //   for (iterator.reset(); !iterator.atEnd(); iterator++) {
00244 //     const Matrix<Float>& cursor = iterator.matrixCursor();
00245 //     for (uInt col = 0; col < nCols; col++) {
00246 //       for (uInt row = 0; row < nRows; row++) {
00247 //         spectrum(channel) += cursor(col, row);
00248 //       }
00249 //     }
00250 //     channel++;
00251 //   } // for iterator
00252 //   cout << "Average spectrum is: " 
00253 //        << spectrum / cursorShape.product() << endl;
00254 // }
00255 // </srcblock>
00256 // </example>
00257 
00258 // <motivation>
00259 // Moving through a Lattice by equal sized chunks, and without regard
00260 // to the nature of the data, is a basic and common procedure.  
00261 // </motivation>
00262 
00263 //# <todo asof="1995/08/28">
00264 //# </todo>
00265 
00266 
00267 class LatticeStepper: public LatticeNavigator
00268 {
00269 public:
00270 
00271   // The hangOverPolicy enumerator is used in the constructors to indicate
00272   // what this class should do when the cursor shape hangs over the edge
00273   // of the Lattice. 
00274   enum hangOverPolicy {
00275   // PAD is the default and means that the cursor size supplied by the user is
00276   // kept fixed. But if the cursor overhangs the Lattice the part that
00277   // overhangs is filled with a default value that is specified by the
00278   // Iterator. Currently the default value is zero. 
00279   PAD,
00280   // RESIZE means that the cursor shape is adjusted whenever it approaches the
00281   // edges of the Lattice so that it is always the right size to include only
00282   // the parts of the Lattice that are available. The user specified cursor
00283   // shape now becomes the default and largest possible cursor shape. 
00284   RESIZE};
00285 
00286   // The first argument is the shape of the Lattice to be iterated and the
00287   // second argument is the shape of the cursor. The cursor will increment
00288   // initially along first axis, then the second and then the third
00289   // (ie. axisPath = IPosition(ndim,0,1,2,...))
00290   // The dimensionality of the cursorShape can be less than the
00291   // dimensionality of the lattice. It will be padded with 1s.
00292   // <br>The cursorShape axes with length > 1 are seen as the true cursor axes.
00293   // The other axes are degenerated and are removed by the functions
00294   // <src>vectorCursor()</src>, etc., in class
00295   // <linkto class=RO_LatticeIterator>(RO_)LatticeIterator</linkto>.
00296   LatticeStepper (const IPosition& latticeShape, const IPosition& cursorShape,
00297                   const uInt hangOverPolicy=PAD);
00298 
00299   // Same as the above constructor except that the axis path is explicitly
00300   // specified. The axis path is described in the synopsis above. 
00301   LatticeStepper (const IPosition& latticeShape, const IPosition& cursorShape,
00302                   const IPosition& axisPath, const uInt hangOverPolicy=PAD);
00303   
00304   // Same as the above constructor except that the cursor axes are
00305   // explicitly specified. This can be useful to avoid that cursor axes
00306   // with length=1 are treated as degenerated axes by the Iterator classes.
00307   // The following rules have to be obeyed:
00308   // <br>- <src>cursorAxes.nelements() <= latticeShape.nelements()</src>
00309   // <br>- <src>cursorShape.nelements() == latticeShape.nelements()</src>
00310   // <br>or <src>cursorShape.nelements() == cursorAxes.nelements()</src>
00311   // The latter means that the cursorShape contains the axes mentioned in
00312   // cursorAxes.
00313   // <br>See also the example in the synopsis.
00314   LatticeStepper (const IPosition& latticeShape, const IPosition& cursorShape,
00315                   const IPosition& cursorAxes,
00316                   const IPosition& axisPath, const uInt hangOverPolicy=PAD);
00317   
00318   // The copy constructor uses copy semantics.
00319   LatticeStepper (const LatticeStepper& other);
00320     
00321   ~LatticeStepper();
00322 
00323   // The assignment operator uses copy semantics.
00324   LatticeStepper& operator= (const LatticeStepper& other);
00325 
00326   // Increment operator (postfix version) - move the cursor
00327   // forward one step. Returns True if the cursor was moved.
00328   virtual Bool operator++(int);
00329 
00330   // Decrement operator (postfix version) - move the cursor
00331   // backwards one step. Returns True if the cursor was moved.
00332   virtual Bool operator--(int);
00333 
00334   // Function to move the cursor to the beginning of the (sub)-Lattice. Also
00335   // resets the number of steps (<src>nsteps</src> function) to zero. 
00336   virtual void reset();
00337 
00338   // Function which returns "True" if the cursor is at the beginning of the
00339   // (sub)-Lattice, otherwise, returns "False"
00340   virtual Bool atStart() const;
00341 
00342   // Function which returns "True" if an attempt has been made to increment
00343   // the cursor beyond the end of the (sub)-Lattice.
00344   virtual Bool atEnd() const;
00345 
00346   // Function to return the number of steps (increments & decrements) taken
00347   // since construction (or since last reset).  This is a running count of
00348   // all cursor movement (operator++ or operator--), even though
00349   // N-increments followed by N-decrements will ALWAYS leave the cursor in
00350   // the original position.
00351   virtual uInt nsteps() const;
00352 
00353   // Functions which return the current position of the beginning of the
00354   // cursor. The <src>position</src> function is relative to the origin
00355   // in the main Lattice and the <src>relativePosition</src> function is
00356   // relative to the origin and increment used in the sub-Lattice (defined
00357   // using the <src>subSection</src> function). If no sub-Lattice is defined
00358   // the two functions return identical positions.
00359   // <group>
00360   virtual IPosition position() const;
00361   virtual IPosition relativePosition() const;
00362   // </group>
00363 
00364   // Functions which return the current position of the end of the
00365   // cursor. The <src>endPosition</src> function is relative to the origin
00366   // in the main Lattice and the <src>relativeEndPosition</src> function
00367   // is relative to the origin and increment used in the sub-Lattice
00368   // (defined using the <src>subSection</src> function). If no sub-Lattice
00369   // is defined the two functions return identical positions.
00370   // <note role=caution> It returns the end position in the lattice and
00371   // does not take overhang into account. </note>
00372   // <group>
00373   virtual IPosition endPosition() const;
00374   virtual IPosition relativeEndPosition() const;
00375   // </group>
00376 
00377   // Functions which return the shape of the Lattice being iterated
00378   // through. <src>latticeShape</src> always returns the shape of the main
00379   // Lattice while <src>subLatticeShape</src> returns the shape of any
00380   // sub-Lattice defined using the <src>subSection</src> function. 
00381   // <group>
00382   virtual IPosition latticeShape() const;
00383   virtual IPosition subLatticeShape() const;
00384   // </group>
00385 
00386   // Functions to change the cursor shape to a new one. They always reset
00387   // the cursor to the beginning of the Lattice (and reset the number of
00388   // steps to zero).
00389   // <group>
00390   void setCursorShape (const IPosition& cursorShape);
00391   void setCursorShape (const IPosition& cursorShape,
00392                        const IPosition& cursorAxes);
00393   // </group>
00394 
00395   // Function which returns the shape of the cursor. This always includes
00396   // all axes (ie. it includes degenerates axes)
00397   virtual IPosition cursorShape() const;
00398 
00399   // Function which returns the axes of the cursor.
00400   virtual IPosition cursorAxes() const;
00401 
00402   // Function which returns "True" if the increment/decrement operators have
00403   // moved the cursor position such that part of the cursor beginning or end
00404   // is hanging over the edge of the (sub)-Lattice.
00405   virtual Bool hangOver() const;
00406 
00407   // Functions to specify a "section" of the Lattice to step over. A section
00408   // is defined in terms of the Bottom Left Corner (blc), Top Right Corner
00409   // (trc), and step size (inc), on ALL of its axes, including degenerate
00410   // axes. The step size defaults to one if not specified.
00411   // <group>
00412   virtual void subSection (const IPosition& blc, const IPosition& trc);
00413   virtual void subSection (const IPosition& blc, const IPosition& trc, 
00414                            const IPosition& inc);
00415   // </group>
00416 
00417   // Return the bottom left hand corner (blc), top right corner (trc) or
00418   // step size (increment) used by the current sub-Lattice. If no
00419   // sub-Lattice has been defined (with the <src>subSection</src> function)
00420   // these functions return blc=0, trc=latticeShape-1, increment=1, ie. the
00421   // entire Lattice.
00422   // <group>
00423   virtual IPosition blc() const;
00424   virtual IPosition trc() const;
00425   virtual IPosition increment() const;
00426   // </group>
00427 
00428   // Return the axis path.
00429   virtual const IPosition& axisPath() const;
00430 
00431   // Function which returns a pointer to dynamic memory of an exact copy 
00432   // of this instance.  The pointer returned by this function must
00433   // be deleted externally.
00434   virtual LatticeNavigator* clone() const;
00435 
00436   // Function which checks the internal data of this class for correct
00437   // dimensionality and consistant values. 
00438   // Returns True if everything is fine otherwise returns False
00439   virtual Bool ok() const;
00440 
00441   // Calculate the cache size (in tiles) for this type of access to a lattice
00442   // in the given row of the tiled hypercube.
00443   virtual uInt calcCacheSize (const IPosition& cubeShape,
00444                               const IPosition& tileShape,
00445                               uInt maxCacheSize, uInt bucketSize) const;
00446 
00447 private:
00448   // Prevent the default constructor from being used.
00449   LatticeStepper();
00450   // Pad the cursor to the right number of dimensions.
00451   void padCursor();
00452   // Check if the cursor shape is a factor of the Lattice shape.
00453   Bool niceFit() const;
00454 
00455 
00456   LatticeIndexer itsIndexer;//# Knows about the (sub)-Lattice shape and how
00457                             //# to traverse it.
00458   IPosition itsCursorAxes;  //# the cursor axes
00459   IPosition itsCursorShape; //# The shape of the cursor
00460   IPosition itsCursorPos;   //# The current position of the iterator.
00461   IPosition itsAxisPath;    //# the heading to follow for the cursor 
00462   uInt itsNsteps;           //# the number of iterator steps taken thus far; 
00463                             //# set to 0 on reset ()
00464   Bool itsEnd;              //# is the cursor beyond the end?
00465   Bool itsStart;            //# is the cursor at the beginning?
00466   Bool itsNiceFit;          //# if the cursor shape is a sub-multiple of the
00467                             //# Lattice shape then set this to True. Used to
00468                             //# avoid needing to test for a cursor hanging
00469                             //# over the edge of the lattice.
00470   Bool itsHangover;         //# this data member is set by the increment and
00471                             //# decrement operators if itsNiceFit == False. It
00472                             //# is used to tell if the cursor "Hangs over"
00473                             //# the edge of the lattice shape.
00474   uInt itsPolicy;           //# what to do if the cursor does hang over
00475 };
00476 
00477 
00478 
00479 } //# NAMESPACE CASA - END
00480 
00481 #endif